0

My team and I are writing a web-app in PHP5.5, with a database that (amongst other things) has a typical username and passhash lookup for user authentication.

We're looking at ways of preventing more than a relative number, say 8, incorrect logins. This is a web-app for about 7000 students, whom when on one of 4 campuses networks, will all share the same outgoing IP address. Currently, failed log ins are logged in a table as a timestamp and an IP address, as well as the username attempted (which is a foreign key) or NULL if the username was incorrect.

We've thought of some methods already, but all pose a security flaw or issue:

  • Storing the user-agent string: Many computers are standardised across the schools and produce identical user agent strings

  • Storing local/network IP addresses: Currently no reliable and efficient method of evaluating this

  • Give each user a unique ID and store in cookie: Sessions can easily be refreshed, cache cleared, different browser, etc.

If there is some way of reliably identifying users behind a small network address using PHP or MySQL, ideally we'd be comparing the number of recent login attempts from that address. This way we'd be able to lockout (serverside) just that one user.

I'm wondering what methods sites with larger userbases use effectively.

Reece Como
  • 75
  • 9
  • 4
    lock on a per account basis, instead of per ip. problem solved. – r3wt Jul 26 '14 at 02:19
  • No site I have seen, even major hosting providers, choose to automate this. They enable alerts, and then they block IP addresses manually. – Bill Karwin Jul 26 '14 at 02:19
  • *"Give each user a unique ID and store in cookie: Sessions can easily be refreshed, cache cleared, different browser, etc."* - Actually, cookies can be cleared; sessions on the other hand, are server-side and are unique to the user. – Funk Forty Niner Jul 26 '14 at 02:20
  • 2
    @Fred-ii-, the user can clear the cookie that stores the session ID, which will force the web server to generate a new session for the user. Same problem as using cookies. – David Jul 26 '14 at 02:21
  • @David Sidenote: http://stackoverflow.com/a/1085792/ – Funk Forty Niner Jul 26 '14 at 02:23
  • @Fred-ii-, HttpOnly cookies can be deleted just as easily. Either you use a custom program to brute force and you don't save cookies. Or you keep clearing the cookies for that website each time you try a new login attempt. – David Jul 26 '14 at 02:26
  • @David Then Gumbo's answer needs some clarification/update then (mind you, it does date back to 2009). So, as r3wt states, a per account seems to be the best solution so far. – Funk Forty Niner Jul 26 '14 at 02:28
  • @r3wt Any anonymous user would be able lock any user account out by spamming their account username - this method would introduce more problems than it solves. – Reece Como Jul 26 '14 at 03:07
  • @Fred-ii- Sessions would have to work with cookies in order to track anonymous users -> and sessions can still be refreshed by changing browsers, clearing cookies, etc. – Reece Como Jul 26 '14 at 03:09
  • @r3wt Logins ARE done by email (The usernames ARE unique email addresses). I don't see how this changes anything. Email addresses are in the format studentnumber@schoolname.edu.au, so if I know another students number, I can lock them out. – Reece Como Jul 26 '14 at 03:12
  • then perhaps you should rethink the design of your application. i'm not casting stones and i realize you are working in a university setting. thinking outside of the box a bit, you could use some type of java applet or pixel tracking image but i'm not sure how effective it would be. i'm going to forward this question to someone who might know a bit more about it than me. – r3wt Jul 26 '14 at 03:31
  • You could use sessions and tokens. Here's a link to a page with code I've used before **http://www.phpro.org/tutorials/Preventing-Multiple-Submits.html** whether that will work or not. Also have a look at this guy's blog **http://blog.ircmaxell.com/** he's also [**a member here**](http://stackoverflow.com/users/338665/ircmaxell) on SO. The guy's an absolute guru when it comes to security-related issues. Go through some of his stuff, you might find something that could be useful; good luck. – Funk Forty Niner Jul 26 '14 at 04:38

4 Answers4

3

The standard approach here is a tar pit. Just slow them down so it's infeasible to brute force attack an account.

Another approach is a captcha after so many failed attempts on a particular account. The only draw back is the victim will know they're under attack if they have to enter a captcha for their account.

This assumes everyone has a strong password. Enforce strong (long, non-dictionary) passwords.

With this approach, it's rarely necessary to lock down the account that is being attacked, though you could notify them if you wish.

Funk Forty Niner
  • 74,450
  • 15
  • 68
  • 141
Marcus Adams
  • 53,009
  • 9
  • 91
  • 143
2

I think we're going to go for a time lockout/CAPTCHA combination.

  • When users attempt to login > 3 times for the same account, they will be asked to complete an in-house CAPTCHA along with their login.

  • If they fail the CAPTCHA twice, the account will be locked out from that IP address for 5 minutes. (and then 10, and then 20, etc - for each subsequent attempt)

  • In the case of 8 or more failed attempts - a user could be emailed a link containing a unique identifier that will allow them to either skip the lockout period and/or reset their password. Similar to a forgot password, except they can also retain their password if they wish.

Additional Measures

  • If more than 3 different IP addresses attempt to login to one account with no success in a half hour period - force CAPTCHA on for the next hour, or until successful login from one of the initial 3 IP addresses.

The benefits of this approach are that genuine users wont be locked out as a result of failed brute-force attempts, particularly if the attacker is on a different network.

Reece Como
  • 75
  • 9
  • I'm always "skeptical" to in-house captcha's. I know someone that tried it and this was [his feat](http://chat.stackoverflow.com/transcript/message/15956018#15956018). Although he did add some "lines" to the characters, it was still easy to bypass it by applying some filters... So most of the times I suggest using a well known reputed captcha system that has been proven to be strong enough – HamZa Jul 26 '14 at 04:05
  • 1
    In reality, there's not much incentive to hack a user account on this web-app - with that said -> **Captcha** is more of a "slow-me-down" for the fourth and fifth login attempts. Cheers for your suggestion, we might take it on board (Although the preference is for the server to not be dependent on any other services) – Reece Como Jul 26 '14 at 05:23
1

Recently I've read about a canvas trick to identify users unique. I did not understand this concept completely, but it has to do with the fact that canvas has on every machine very small differences when rendering stuff. addthis.com e.g. uses this to identify. Not a very gentle solution, IMO.

The technique is called: Canvas Fingerprinting.

Here a good resource: http://browserleaks.com/canvas

Armin
  • 15,582
  • 10
  • 47
  • 64
  • I'm afraid HTML5 Canvas Fingerprinting won't be an acceptable solution as half of the campus computers are still running old versions of IE that don't fully support HTML4, let alone 5. – Reece Como Jul 26 '14 at 03:10
0

If clients are new enough you may be able to take advantage of webRTC. Here is an example that dumps the whole packet out to the screen and logs individual ip address in the console. You could send those to the server with javascript and use them to block.

<html>
 <head>
  <title>Test</title>
  <script>
     function grepSDP(sdp) {
       var hosts = [];
       sdp.split('\r\n').forEach(function (line) {
           if (~line.indexOf('a=candidate')) {
               var parts = line.split(' '),
                   addr = parts[4],
                   type = parts[7];
               if (type === 'host')
                   console.log(addr);
           } else if (~line.indexOf('c=')) {
               var parts = line.split(' '),
               addr = parts[2];
               console.log(addr);
           }
    });
   }

   var peer = new webkitRTCPeerConnection({'iceServers': [{'url': 'stun:stun.services.mozilla.com'}]});
   peer.createOffer(function(sdp) { peer.setLocalDescription(sdp); }, function(err) { console.error(err); }, {});
   setTimeout(function() {
        grepSDP(peer.localDescription.sdp);
        document.getElementById("localdescription").innerHTML = peer.localDescription.sdp;
       }, 500);
  </script>
 </head>
 <body>
  Local description:
  <div id="localdescription">
 </body>
</html>
williamt
  • 413
  • 2
  • 4
  • 15
  • Two major flaws here: users can disabled JavaScript, as well as spoof IP information. – Reece Como Jul 26 '14 at 03:19
  • I suppose you could force them to have JavaScript enabled otherwise the app would fail. Spoofing could/would be possible. I guess it depends on what you are trying to protect. Another option is a java implementation with ssl transport so they can't spoof. – williamt Jul 26 '14 at 04:32