time warner cable – different person, different problem?

I haven’t a problem that was maddening when dealing with Time Warner since 2010. It’s that time again.

Background

My cable/DVR box has been slowing getting worsening problems for a while:

  1. freezing periodically for a few seconds
  2. saying there was 0% recorded (a reboot solved that, but it happened about once a month)
  3. turning off and not recording with a reboot. then after the reboot would start recording the middle of a show as if it were a long standing agreement

As I had shows I wanted to watch on the DVR, I chose to live with the first two problems. The third one is core functionality of a DVR so had to deal with it and get a different DVR.

Saturday

I went to the Time Warner store. I returned the Scientific American box and was given a “new” Samsung box. And by “new” I mean a box that someone else returned, they presumably tested and then gave to me. Here’s what happened:

  1. I plugged in the box and it told me to call Time Warner to activate. I haven’t had to do that when trading boxes in the past, but ok. That’s reasonable. They activated the box and had me restart the box. I appeared to have TV.
  2. I went to “Free Primetime On Demand” and got a message to call Time Warner. The rep says she needs to check if it is on my plan. It is FREE primetime on demand. I’m pretty sure it is on everyone’s plan. (This is the station for network tv after it airs. Which I wanted to watch because my DVR wasn’t working last week when I tried to record them.) She eventually gets back to me and agrees I should have it. Guess what the solution was? Reboot the box. I imagine she did something at her end as well.
  3. A little later in the day, I found that cable stations would freeze after a few seconds of play. Network stations (over the air equivalents) played just fine. When I called time warner she “runs a signal test” and tells me the problem is with the box and they can send a tech. If the problem is with the box, I can go to the store and trade boxes again. I don’t need to wait for a tech. When I complain I don’t want to wait for a tech, she tells me it won’t come until Tuesday if they mail a box. I don’t want them to mail the box. I then tried rebooting again.
  4. Provisioning – H/E error – We never got to the bottom of this one although it sounds like an issue with the box. (I also had noCP, but that was when I had the box plugged in wrong.) The tech “ran a signal test.” The tech claimed the provisioning error was because it was a used box and it was downloading updates. At 6:30pm, the rep says she will call me back at 8:30pm to follow up.
  5. She calls at just before 11pm. That’s late to be calling someone. What if I had children who were sleeping? At 11pm, she “ran a signal test” and told me the problem was with the box.

Sunday

Back to the Time Warner store. The rep lives near me and asked if there was construction nearby. There was. He then runs a signal test and tells me there is a problem with the signal. As I spoke to several people who did that the previous day who “ran a signal test”, I was suspicious. He shows me a red screen. However, the cable box was in my hand rather than plugged in at home so still suspicious. He tells me that they need to send a tech to check/fix the signal. Sigh. I give up. Fine. I’ll arrange to be home for a tech to come.

Monday

I had an appointment for between 3 and 4pm. That gave me time to work for half a day in the office and telecommute the rest of the day. I got home around 2pm. I have two messages on my cell phone voicemail and one on my home phone. Two messages say that if I don’t pick up, my appointment will be cancelled. The last says my appointment is confirmed and the tech will call before coming up. Weird.

Since I had time, I decided to go buy lunch. I get back at 2:15pm. At 2:21pm, the tech arrives. That’s not between 3 and 4. What if I wasn’t home? Would I have missed my appointment?

The tech said the problem was the box. (No kidding, this was apparent on Saturday.) He installed a new box. A brand new box.  This time a Cisco one. Which requires over 40 minutes of software downloads before it starts. Which their tech had to be here for. So he got paid to watch videos on my couch for almost an hour. This isn’t his fault. The tech did a great job. He was helpful and polite. Just not necessary. I am perfectly capable of plugging in a box and waiting for an hour.

 

fixing clickjacking and brute force login for jforum

I’ve been blogging about some of the security fixes we’ve made in the CodeRanch fork of JForum such as XSS with quotes and CSRF. Today it is time to write about Clickjacking and preventing brute force logins.

Clickjacking

Clickjacking is an attack where someone includes your site in transparent frames and the attacker intercepts anything typed in/clicked. We had originally decided not to do anything about ClickJacking because we want our site to be available in frames. For example, DZone serves the main page in a frame when asking people to vote on it.

However, that doesn’t mean that we shouldn’t protect anything. We decided to protect the most critical parts of the site – the admin screens and the login form. That leaves the read only pages (which we don’t mind framed) and editing posts/user info (which is displayed publicly anyway).

The implementation turned out to be simple. We added this header to the relevant pages. (the admin screens are always within a frame on the site and the login screen is when an admin’s session times out).

response.setHeader("X-Frame-Options", "SAMEORIGIN");

It turned out the method only needed to be called from two places: UserAction (for login) and the AdminCommand (for the admin console).

While this isn’t complete protection, it is certainly better than the nothing we had before. And it is easy to add more screens in the future if we need to. We also didn’t include the JavaScript framebusting logic for older browsers because Google Analytics says hardly of our users are on such browsers.

Preventing Brute Force Logins

Another security issue that we knew about but didn’t fix because “it wasn’t a problem” was preventing brute force logins. It seemed like high time to do something about that one too. While this was more work than fixing Clickjacking, it wasn’t a huge deal either. The logic is mostly in one (well unit tested) class that gets called from the method with the login check. There is also a property file to externalize the number of attempts/wait. And a job to clear out the Map once a day for attempts where the IP gives up and goes away.

The idea is that an IP gets a number of “free” attempts. After that more login attempts from that IP must wait longer and longer. Once a user logs in successfully from that IP or there are no attempts for a certain amount of time,t he clock starts over and the “free” attempts are back.

This approach doesn’t protect against a distributed attack because the IPs are different. (I choose the IP based approach so someone can’t lock out a user’s account specifically by targeting them and entering invalid passwords. That said, we aren’t running a bank so it seems unlikely for someone to go through that much effort to attack us.

Note: I got a private comment to be careful about IP blocking due to companies using a single public IP for thousands of users. This approach is NOT using IP blocking. Let’s say have 1000 users from InfoSys. (We probably have more, but that’s not the point.) Most of those users will either know their password or use the “remember password” functionality. If a few forget their password and type in a bunch of wrong attempts, the time throttling kicks in.  It seems unlikely for multiple users to having this problem at the same time. And as soon as anyone from the company (IP) has a correct password, the “penalty” count resets.

Code for the curious:

package net.jforum.repository;

import java.util.*;

import net.jforum.util.preferences.*;

/**
 * We prevent brute force login attacks by throttling how often we will check
 * credential after three failed logins from the same IP since the last success.
 * If there are no failures within an hour, the clock will restart on this
 * throttling.
 *
 * @author Jeanne
 * @version $Id: $
 */
public class FailedLoginRepository {
    private static final int NUM_SECONDS_IN_MINUTE = 1000 * 60;
    private static FailedLoginRepository cache = new FailedLoginRepository();
    private Map<String, List<Date>> failedLogins;
    private int maxLoginsBeforeThrottling;
    private int numMinutesForReset;
    private int[] throttlingDelay;

    // ----------------------------------------------------------------
    public FailedLoginRepository() {
        failedLogins = new HashMap<String, List<Date>>();
        numMinutesForReset = SystemGlobals.getIntValue(ConfigKeys.BRUTE_FORCE_PREVENTION_NUM_MINUTES_FOR_RESET);
        String waitTimes = SystemGlobals.getValue(ConfigKeys.BRUTE_FORCE_PREVENTION_WAIT_TIMES);
        setWaitsAsIntArray(waitTimes);
        setMaxLoginsBeforeThrottling();
    }

    private void setMaxLoginsBeforeThrottling() {
        for (int i = 0; i < throttlingDelay.length; i++) {
            if (throttlingDelay[i] == 0) {
                maxLoginsBeforeThrottling++;
            }
        }
    }

    private void setWaitsAsIntArray(String waitTimes) {
        String[] stringArray = waitTimes.split(",");
        throttlingDelay = new int[stringArray.length];
        for (int i = 0; i < throttlingDelay.length; i++) {
            throttlingDelay[i] = Integer.parseInt(stringArray[i].trim());
        }
    }

    // ----------------------------------------------------------------
    public static FailedLoginRepository getInstance() {
        return cache;
    }

    // ----------------------------------------------------------------
    /**
     * After a successful login from the API, remove the blocks. This indicates
     * the user just mistyped and not a hacker.
     *
     * @param ip
     */
    public void successfulAttempt(String ip) {
        failedLogins.remove(ip);
    }

    // ----------------------------------------------------------------
    /**
     * Keep track of time of login failure
     *
     * @param ip
     * @param now
     */
    public void failedAttempt(String ip, Date now) {
        removeOldAttempts(ip);
        List<Date> fails = failedLogins.get(ip);
        if (fails == null) {
            fails = new ArrayList<Date>();
            failedLogins.put(ip, fails);
        }
        fails.add(now);
    }

    public void failedAttempt(String ip) {
        failedAttempt(ip, new Date());
    }

    // ----------------------------------------------------------------
    /**
     * If there haven't been any failed attempts from that IP in the last hour,
     * start over.
     *
     * @param ip
     */
    private void removeOldAttempts(String ip) {
        List<Date> fails = failedLogins.get(ip);
        if (fails != null) {
            Date lastFail = getLastFail(fails);
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.MINUTE, -numMinutesForReset);
            if (lastFail.before(cal.getTime())) {
                failedLogins.remove(ip);
            }
        }
    }

    private Date getLastFail(List<Date> fails) {
        Date lastFail = fails.get(fails.size() - 1);
        return lastFail;
    }

    public void removeAllOldAttempts() {
        for (String ip : failedLogins.keySet()) {
            removeOldAttempts(ip);
        }
    }

    // ----------------------------------------------------------------
    public boolean shouldCheckPassword(String ip) {
        removeOldAttempts(ip);
        int waitRemaining = numberMinutesUntilNextAllowedLogin(ip, new Date());
        return waitRemaining == 0;
    }

    public boolean shouldCheckPassword(String ip, Date now) {
        removeOldAttempts(ip);
        List<Date> fails = failedLogins.get(ip);
        return fails == null || fails.size() <= maxLoginsBeforeThrottling;
    }

    // ----------------------------------------------------------------
    public int numberMinutesUntilNextAllowedLogin(String ip) {
        return numberMinutesUntilNextAllowedLogin(ip, new Date());
    }

    /**
     * Contains algorithm for delays: see if already waited number of minutes
     * need to wai
     *
     * @param ip
     * @return
     */
    public int numberMinutesUntilNextAllowedLogin(String ip, Date now) {
        List<Date> fails = failedLogins.get(ip);
        if (fails == null) {
            return 0;
        }
        int index = fails.size() - 1;
        if (index >= throttlingDelay.length) {
            index = throttlingDelay.length - 1;
        }
        int delay = throttlingDelay[index];
        Date lastFailure = getLastFail(fails);
        int numMinutesWaited = (int) (now.getTime() - lastFailure.getTime()) / NUM_SECONDS_IN_MINUTE;
        int result = delay - numMinutesWaited;
        // if delay is over, do need to wait longer
        if (result < 0) {
            result = 0;
        }
        return result;
    }
}

 

Announcing the OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide

Jeanne and I are pleased to announce the upcoming release of our Oracle Certified Associate Java 8 Study Guide for the Java SE 8 Oracle Programmer I exam! We have been working with Wiley Publishing for the past year to bring this book to light, and are thrilled to announce it is nearing completion. Our goal was create a book that is engaging and fun for new and veteran developers alike. The book covers all of the new features that you are required to know for the OCA 8 exam including: the Local Date/Time API, the Period class, lambda expressions, and more. And of course, it covers the “old” topics as well.

scott-and-jeanne
The book, to be tentatively titled OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide: Exam 1Z1-808, will be available for purchase later this year on Amazon.com and wherever books are sold.

Oracle has already published a beta version of the Java SE 8 Programmer I exam, with the official version to be available in the coming months.

Please visit our new OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide page for the latest information about the book. If you have any questions for us, feel free to post in the OCA forum at CodeRanch, which Jeanne and Scott visit frequently.