Asked  7 Months ago    Answers:  5   Viewed   31 times

I have my login page and of course I want to prevent brute force attacks and cause less delay for the users when they are logging in.

Currently, you type in your username and password to log in.

I am considering implementing a reCAPTCHA. However, this shows on login after 3 failed attempts.

My question is:

  1. What do you base the attempt on. IP addresses? It can always be hidden... username? What if they're trying a user that doesn't exist?

  2. What would be the best method to count the failed login attempts?

 Answers

73

Sessions are unreliable because they rely on cookies, CAPTCHAs are regularly broken [including ReCAPTCHA]. The only reliable method is deceptively simple: ask a question. Don't use a math question because computers are surprisingly adept at solving those for some reason. Great old standbys are things like:

  • What is the fourth word in the sixth paragraph on this page?
  • What is the name of the author of this site? [hint]

This is stupid-easy to implement, and very difficult for a machine to solve.

As for bute-forcing, try adding two fields to your user table, 'first_failed_login' [INTEGER unix timestamp or DATETIME] and 'failed_login_count'. [INTEGER]

<?php
$bad_login_limit = 3;
$lockout_time = 600;

$first_failed_login, failed_login_count; // retrieve from DB

if(
    ($failed_login_count >= $bad_login_limit)
    &&
    (time() - $first_failed_login < $lockout_time)
) {
  echo "You are currently locked out.";
  exit; // or return, or whatever.
} else if( /* login is invalid */ ) {
  if( time() - $first_failed_login > $lockout_time ) {
    // first unsuccessful login since $lockout_time on the last one expired
    $first_failed_login = time(); // commit to DB
    $failed_login_count = 1; // commit to db
  } else {
    $failed_login_count++; // commit to db.
  }
  exit; // or return, or whatever.
} else {
  // user is not currently locked out, and the login is valid.
  // do stuff
}

This will make your login system recognize only 3 login attempts per user every 10 minutes.

Wednesday, March 31, 2021
 
jakubos
answered 7 Months ago
12

i would prefer that instead of having a PHP process send the file and hog server resources for long while its sending the content.. create a script which copies the file over to a directory with a random name and then just send that file to the user and have another script clear out that directory after set intervals .. if creation time older than 30 mins .. delete .. that way u minimize u just need an apache process to send back the file instead of apache + php process.

Saturday, May 29, 2021
 
CMOS
answered 5 Months ago
90

Hope this helps you solve the problem. As for right now, your keyGen() is equivalent to the following code:

public String keyGen() {
    return "!!!!!!!!";
}

because you return the value as soon as you enter the innermost for loop. Maybe you want to change the method to return a List<String> and add your strings in the innermost for loop to that list, and return that list after all of the for loops? This way you could iterate through the list in your main method.


If I have counted correct, there are 93^8 = 5.595.818.096.650.401 different strings. It was bad advice to store all those in a list. Dukeling noted in the comments, that it would be better to use a custom Iterator<String> for that.


EDIT

Here's an implementation of such an iterator:

import java.util.Arrays;
import java.util.Iterator;

public class BruteForceIterator implements Iterator<String> {

    private char min, max;

    private char[] current;

    private char[] last;

    private int reachedLast = 0;

    public BruteForceIterator(char min, char max, int length) {
        this.min = min;
        this.max = max;
        current = new char[length];
        Arrays.fill(current, min);
        last = new char[length];
        Arrays.fill(last, max);
    }

    @Override
    public boolean hasNext() {
        return reachedLast < 2;
    }

    @Override
    public String next() {
        String str = new String(current);
        for(int i = current.length - 1; i >= 0; i--) {
            char next = following(current[i]);
            current[i] = next;
            if (next != min) {
                break;
            }
        }
        if (Arrays.equals(current, last) || reachedLast > 0) {
            reachedLast++;
        }
        return str;
    }

    private char following(char in) {
        if (in < max) {
            return (char) (in + 1);
        } else {
            return min;
        }
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("No with me, sir!");
    }

    public static void main(String[] args) {
        BruteForceIterator bit = new BruteForceIterator('a', 'c', 3);
        while (bit.hasNext()) {
            System.out.println(bit.next());
        }
    }
}
Saturday, August 7, 2021
 
binoculars
answered 3 Months ago
72

Code first:

from itertools import product

chars = '0123456789' # chars to look for

for length in range(1, 3): # only do lengths of 1 + 2
    to_attempt = product(chars, repeat=length)
    for attempt in to_attempt:
        print(''.join(attempt))

itertools.product produces a Cartesian join of its input(s) - in this case, it's being 'joined' to itself. So in the first iteration, each single character is printed. Then in the next iteration, because of repeat=length (and length is now == 2), generates '00', '01', etc... It's worth trying it and seeing the output to understand it better.

This also means you can throw in letters (uppercase/lowercase), and change the upperbound in the range function.

It's certainly not going to break the world of code-breaking, but should give you an idea of the flexibility of Python and the tools available to you.

I'll leave you to check the passwords match and break out the loop.

Wednesday, August 11, 2021
 
Josip Valčić
answered 3 Months ago
67

Define a constraint: entity_id_a < entity_id_b.

Create indexes:

CREATE UNIQUE INDEX ix_a_b ON entity_entity(entity_id_a, entity_id_b);
CREATE INDEX ix_b ON entity_entity(entity_id_b);

Second index doesn't need to include entity_id_a as you will use it only to select all a's within one b. RANGE SCAN on ix_b will be faster than a SKIP SCAN on ix_a_b.

Populate the table with your entities as follows:

INSERT
INTO entity_entity (entity_id_a, entity_id_b)
VALUES (LEAST(@id1, @id2), GREATEST(@id1, @id2))

Then select:

SELECT entity_id_b
FROM entity_entity
WHERE entity_id_a = @id
UNION ALL
SELECT entity_id_a
FROM entity_entity
WHERE entity_id_b = @id

UNION ALL here lets you use above indexes and avoid extra sorting for uniqueness.

All above is valid for a symmetric and anti-reflexive relationship. That means that:

  • If a is related to b, then b is related to a

  • a is never related to a

Friday, October 1, 2021
 
c_k
answered 3 Weeks ago
c_k
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :