<html> | |
<head></head> | |
<body> | |
<h1>NoCaptcha</h1> | |
<h2>Background</h2> | |
<p>This script shows that rate limiting can be passed off to the client. </p> | |
<p>This is extremely advantageous on a network like TOR where normal rate-limiting and utilities like Fail2Ban will not work as every connection is indistinguishable.</p> | |
<h2>Proof of work demo</h2> | |
<p>Once the number is factored into it's constituent primes, the submit button is enabled. The recieving script can use the primes much the same as a captcha.. just stop doing useful work unless the user proves something; in this case, that they spent at least a few seconds factoring a prime</p> | |
<p>Use admin/password for the demo.</p> | |
<?php | |
session_start(); | |
// Never tell the user wether the prime or the password failed. This effectively stops bruteforce attempts and hampers automated signups on hidden services | |
$error_message = "There was an error."; | |
//If we've saved primes and they sent primes, check them | |
if(isset($_POST['prime']) && $_SESSION['primes']){ | |
//If they're valid, great! Keep processing the login. | |
if($_POST['prime'] == $_SESSION['primes'] ){ | |
//Don't ever do this IRL. | |
$credentials = array('admin'=>md5('password')); | |
if(md5($_POST['pass']) === $credentials[$_POST['user']]){ | |
unset($_SESSION['primes']); | |
echo 'Welcome! You\'d likely get redirected at this point.'; | |
} | |
else echo $error_message; | |
} | |
else echo $error_message; | |
} | |
else { | |
// Use way more primes. Like, WAY more primes. Ideally save a few million in a db and use a SQL query to get them at random. This is portable and works good enough for a demo. | |
$primes = array(42920617,42920623,42920641,42920651,42920653,42920681,42920687,42920701,42920741,42920743,42920819,42920827,42920863,42920879,42920887,42920897,42920909,42920929,42920939,42920951,42920953,42920959,42920989,42921001,42921023); | |
$a = $primes[mt_rand(0,count($primes)-1)]; | |
$b = $primes[mt_rand(0,count($primes)-1)]; | |
$primes = array($a, $b); | |
asort($primes); | |
$_SESSION['primes'] = $primes[0].','.$primes[1]; | |
// Include a login script. I've included one inline. | |
?> | |
<form method="post"> | |
<input type="text" name="user" id="user" value ="" placeholder="Username"><br> | |
<input type="password" name="pass" id="pass" value ="" placeholder="Password" ><br> | |
<input type="hidden" name="prime" id="prime" value ="<?php echo $a * $b ?>" > | |
<input type="submit" id="submit" value="Factoring primes..." disabled></input> | |
</form> | |
<script> | |
function factors(num) | |
{ | |
var | |
n_factors = [], | |
i; | |
//skip 1... | |
for (i = 2; i <= Math.floor(Math.sqrt(num)); i += 1) | |
if (num % i === 0) | |
{ | |
n_factors.push(i); | |
if (num / i !== i) | |
n_factors.push(num / i); | |
} | |
n_factors.sort(function(a, b){return a - b;}); // numeric sort | |
console.log(n_factors); | |
return n_factors; | |
} | |
// Ideally we'd do this AFTER the DOM is fully loaded. | |
var result = factors(document.getElementById('prime').value); | |
document.getElementById('prime').value = result; | |
document.getElementById('submit').value = 'Submit'; | |
document.getElementById("submit").disabled = false; | |
</script> | |
<?php } ?> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment