preface
When you learn to write a program, the first line of code is hello world. But when you start learning WEB background technology, The first function of many people is to write login (whispering: I don't know others, but I am anyway). But when I interviewed or communicated with many students with short work experience, I found that although many students wrote on their resumes that they were responsible for the development and design of the login / registration function module of the project, they only simply realized the functional logic and didn't consider too much about security. This article mainly focuses on I want to talk with you. When designing a login interface, it is not only the functional implementation, but also what we need to consider in terms of security.
Safety risk
Brute force cracking!
As long as the website is exposed to the public network, it is very likely to be watched by people. Try to blow up this simple and effective way: after obtaining the user name of the website in various ways, write a program to traverse all possible passwords until the correct password is found
The pseudo code is as follows:
#Password dictionary password_dict = [] #Login interface login_url = '' def attack(username): for password in password_dict: data = {'username': username, 'password': password} content = requests.post(login_url, data).content.decode('utf-8') if 'login success' in content: print('got it! password is : %s' % password) Copy code
So how can we prevent this situation?
Verification Code
Some smart students thought of it. I can add verification code verification when its password error reaches a certain number of times! For example, we set that when the user's password is wrong for 3 times, the user needs to enter the picture verification code before continuing the login operation:
The pseudo code is as follows:
fail_count = get_from_redis(fail_username) if fail_count >= 3: if captcha is None: return error('Verification code required') check_captcha(captcha) success = do_login(username, password) if not success: set_redis(fail_username, fail_count + 1) Copy code
Concurrency is not considered in pseudo code, and locking can be considered in actual development.
This can indeed filter out some illegal attacks, but with the current OCR technology, Ordinary image verification codes are really difficult to effectively prevent robots (we have suffered a great loss on this). Of course, we can also spend money to buy verification schemes such as sliding verification provided by third-party companies, but they are not 100% secure and can be cracked (painful lesson).
login restriction
At that time, another student said that I can directly restrict the login operation of abnormal users. When the password error reaches a certain number of times, I will directly refuse the user's login and recover it after a period of time. For example, if we set an account to make 10 errors during login, all login operations of the account will be rejected within 5 minutes.
The pseudo code is as follows:
fail_count = get_from_redis(fail_username) locked = get_from_redis(lock_username) if locked: return error('Login denied') if fail_count >= 3: if captcha is None: return error('Verification code required') check_captcha(captcha) success = do_login(username, password) if not success: set_redis(fail_username, fail_count + 1) if fail_count + 1 >= 10: #If it fails more than 10 times, set the lock flag set_redis(lock_username, true, 300s) Copy code
umm, which can really solve the problem of user password explosion. However, this will bring another risk: Although the attacker cannot obtain the user information of the website, it can make all users of our website unable to log in! The attacker only needs to iterate through all user names (even if not, random) to log in, then these users will always be locked, resulting in normal users unable to log in to the website!
IP restrictions
Since we can't directly target the user name, we can handle it against the IP. If we directly seal the attacker's IP, everything will be fine. We can set that when the number of errors calling the login interface under an IP reaches a certain number, the login operation of the IP is prohibited.
The pseudo code is as follows:
ip = request['IP'] fail_count = get_from_redis(fail_ip) if fail_count > 10: return error('Login denied') #Other logic # do something() success = do_login(username, password) if not success: set_redis(fail_ip, true, 300s) Copy code
This can also solve the problem to a certain extent. In fact, many current limiting operations are carried out for IP. For example, the current limiting module of niginx can limit the access times of an IP in unit time. But there are still problems:
- For example, many schools and companies now use the same export IP. If they directly press the IP limit, other normal users may be killed by mistake
- With so many VPNs, attackers can switch VPNs to attack after IP is blocked
Mobile phone verification
Isn't there a better way to prevent it? Of course. We can see that in recent years, almost all applications allow users to bind mobile phones. One is the national real name policy requirements, and the other is that mobile phones can basically represent a person's identity like ID cards. Therefore, many security operations are based on mobile phone authentication, and login is also OK.
- When the user enters the password more than 3 times, the user is required to enter the verification code (preferably sliding verification)
- When the user enters the password more than 10 times, the mobile phone authentication will pop up, and the user needs to log in using the dual authentication of mobile phone authentication code and password
Anti brushing of mobile phone verification code is another problem. We won't start here. We'll talk about what we have done in anti brushing of verification code in the future.
The pseudo code is as follows:
fail_count = get_from_redis(fail_username) if fail_count > 3: if captcha is None: return error('Verification code required') check_captcha(captcha) if fail_count > 10: #More than 10 times, log in with verification code and password if dynamic_code is None: return error('Please enter the mobile phone verification code') if not validate_dynamic_code(username, dynamic_code): delete_dynamic_code(username) return error('Mobile phone verification code error') success = do_login(username, password, dynamic_code) if not success: set_redis(fail_username, fail_count + 1) Copy code
We combine the above methods with the verification mode of mobile phone verification code, which can basically prevent a considerable number of malicious attackers. But no system is absolutely safe. We can only increase the attack cost of attackers as much as possible. You can choose the appropriate strategy according to the actual situation of your website.
Man in the middle attack?
What is man in the middle attack
***Man in the middle attack (abbreviated to mitm) * * *, to put it simply, in the process of communication between A and B, the attacker obtains or modifies the communication contents of A and B through sniffing, interception, etc.
For example: Xiaobai sends express to Xiaohuang. On the way, he has to pass through express point A. Xiaohei hides at express point A, or simply opens an express point B to pretend to be express point A. Then he secretly disassembled the express from Xiaobai to Xiaohuang to see what was inside. You can even leave Xiaobai's express and pack A hairy box and send it to Xiaohuang.
In the login process, if the attacker sniffs the login request from the client to the server, he can easily obtain the user's user name and password.
HTTPS
The simplest and most effective operation to prevent man in the middle attack is to replace HTTPS and change all HTTP requests in the website to force the use of HTTPS.
***Why can HTTPS prevent man in the middle attacks*** HTTPS actually adds SSL/TLS protocol between HTTP and TCP protocol to ensure the safe transmission of data. Compared with HTTP, HTTPS has the following characteristics:
- Content encryption
- Data integrity
- Authentication
The specific HTTPS principle is no longer extended here. You can Google by yourself
Encrypted transmission
In addition to HTTPS, we can also encrypt sensitive data manually:
- The user name can be encrypted asymmetrically on the client and decrypted on the server
- The password can be transmitted after MD5 on the client to prevent exposure of password plaintext
other
In addition to what we talked about above, there are many other jobs to consider, such as:
- Operation log: users need to record logs (including IP, devices, etc.) for each login and sensitive operation
- For abnormal operation or login reminder, with the above operation log, we can make risk reminder based on the log. For example, users can send SMS to remind users when they log in, change their password or log in abnormally
- When rejecting weak password} registration or changing password, users are not allowed to set weak password
- Prevent the user name from being traversed. When registering, some websites will prompt whether the user name exists after entering the user name. In this way, there will be a risk that all user names of the website will be leaked (just traverse the interface), which needs to be limited interactively or logically
- ...
Postscript
Now, the state continues to introduce various laws and pay more and more attention to user data. As developers, we also need to do more to protect user data and user privacy. Later, I will also talk with you about what we have done in data security. I hope we can give you a little help.