It is typical for "SEO Marketing Companies" to take advantage of forums and blogs by creating worthless posts and comments with links to a website they are promoting.
If your web-property allows user-generated content, you are likely to use CAPTCHA. CAPTCHAs are not perfect:
Today it is possible to buy access to an API which solves any CAPTCHA for just $0.70 per 1000 CAPTCHA images. And do you think your customer will be happy to try to solve one of these ridiculous CAPTCHAs?
Many modern web-applications are susceptible to brute force attacks.
Take a typical login form, for example. Hackers can compromise account security by trying every possible password combination. They can also leverage a large network of proxy servers to parallelize this attack.
Forcing their browser to work hard makes it too expensive and slow for hackers to perform a brute force attack.
We leverage the following technologies:
Browsers supported:
If you are using custom code or a framework/CMS which is not yet supported, you can use
jQuery.hashcash.io plugin for super simple integration.
Add jquery.hashcash.io.min.js
into the <head>
of your HTML page and call it
for the form which you would like to protect.
On a server side you need to make a single call to hashcash.io server to verify that the work was indeed done.
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link type="text/css" rel="stylesheet" href="jquery.hashcash.io/jquery.hashcash.io.min.css" media="all" />
<script src="jquery.hashcash.io/jquery.hashcash.io.min.js"></script>
</head>
<body>
<form action="/addcomment" method="POST">
<textarea name="comment"></textarea><br />
<input type="submit" value="Submit Comment" />
</form>
<script>
$("form input[type=submit]").hashcash({
key: "YOUR-PUBLIC-KEY"
});
</script>
</body>
</html>
if (! $_REQUEST['hashcashid']) {
die("Please unlock submit button.");
}
$url = 'https://hashcash.io/api/checkwork/' . $_REQUEST['hashcashid'] . '?apikey=[YOUR-PRIVATE-KEY]';
$work = json_decode(file_get_contents($url));
if (! $work) {
die("Please try again");
}
if ($work->verified) {
die("This proof-of-work was already used");
}
if ($work->totalDone < 0.01) {
die("You did not wait long enough");
}
saveAndPublishPost();
# part of the standard Ruby library
require 'open-uri'
require 'json'
# denotes a HTTP route
post '/addcomment' do
id = params[:hashcashid]
privkey = "YOUR_PRIVATE_KEY"
if not id
return { :error => 'Please unlock submit button. }
end
url = "https://hashcash.io/api/checkwork/#{id}?apikey=#{privkey}"
# JSON will break if empty response.
begin
work = JSON.parse(open(url).read)
rescue Exception => e
return { :error => 'Something went wrong.' }
end
if work['verified']
return { :error => 'This proof-of-work was already used' }
end
if work['totalDone'] < 0.01
return { :error => 'You did not wait long enough.' }
end
do_your_thing
end
Courtesy of Maxwell Bernstein
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var restler = require('restler');
var key = "[YOUR PRIVATE KEY]";
var complexity = 0.01;
var validateHashcash = function(req, res, next) {
var id = req.param('hashcashid');
restler.get(
'https://hashcash.io/api/checkwork/' + id,
{ query: { apikey: key }}
).on("success", function(data) {
if (data.verified) {
return res.json({ status: "error", message: "This proof-of-work was already used" });
}
else {
if (data.totalDone > complexity) {
return next();
}
else {
return res.json({ status: "error", message: "Not enough work done" });
}
}
}).on("fail", function() {
return res.json({ status: "error", message: "[fail] Proof of work not calculated" });
}).on("error", function() {
return res.json({ status: "error", message: "[error] Proof of work not calculated" });
});
};
var addcomment = function(req, res) {
return res.json({ status: "success", message: "comment posted" });
};
app.use(bodyParser());
app.post(
'/addcomment',
validateHashcash,
addcomment
);
app.listen(3000);