When you learn to write programs, the first line of code is hello world. But when you start learning WEB background technology, many people's first function is to write login (whisper: I don't know others, but I am anyway).
However, when I interviewed or communicated with many students with a short working experience, I found that many students have written on their resumes: responsible for the development and design of login/registration module of the project, but they are just simple implementation of functional logic, and do not take too much into account in terms of security.
This article is mainly to chat with you. When designing a login interface, it is not only a functional implementation, but also a security consideration.
Security risk
Violence breaks!
As long as the site is exposed to the public, there is a high probability that it will be watched, and an attempt is made to explode this simple and effective way: once the user name of the site has been obtained in various ways, program through all possible passwords until the correct one is found
The pseudocode 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)
So how can we prevent this?
Verification Code
A smart classmate thinks that I can add verification code when its password error reaches a certain number of times! For example, if the user's password has been wrong three times, the user will need to enter a picture authentication code to continue the login operation:
The pseudocode is as follows:
fail_count = get_from_redis(fail_username) if fail_count >= 3: if captcha is None: return error('Authentication code required') check_captcha(captcha) success = do_login(username, password) if not success: set_redis(fail_username, fail_count + 1)
Pseudo-code does not take concurrency into account, and locking can be considered for actual development.
This really filters out some illegal attacks, but with the current OCR technology, ordinary picture validation codes really can't prevent robots effectively (we've lost a lot on this). Of course, we can also spend money on validation schemes like sliding validation provided by a three-party company, but it is not 100% safe and can be cracked (painful lessons).
login restriction
At that time, another classmate said that I can directly restrict the logon operation of abnormal users. When the password error reaches a certain number of times, I can directly refuse the user's logon and recover it after a while. For example, if we set up an account to make 10 errors at login time, we will reject all login operations for that account within 5 minutes.
The pseudocode is as follows:
fail_count = get_from_redis(fail_username) locked = get_from_redis(lock_username) if locked: return error('Deny login') if fail_count >= 3: if captcha is None: return error('Authentication 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: #Failed more than 10 times, set lock flag set_redis(lock_username, true, 300s)
umm, this really solves the problem of user passwords being exploded. However, there is another risk: an attacker can't get the user information of the website, but it can prevent all users of our website from logging in! Attackers only need to iterate through all user names (even if they don't, randomly) in an infinite loop to log in, and these users will always be locked out, preventing normal users from logging in to the website!
IP Restrictions
Since direct targeting of user names is not possible, we can handle it for IP. Blocking an attacker's IP is a great thing. We can set an IP to be prohibited from login operations if the number of errors in calling the login interface under that IP reaches a certain level.
The pseudocode is as follows:
ip = request['IP'] fail_count = get_from_redis(fail_ip) if fail_count > 10: return error('Deny login') #Other logic # do something() success = do_login(username, password) if not success: set_redis(fail_ip, true, 300s)
This can also solve the problem to some extent. In fact, there are many stream limiting operations for IP, such as the niginx stream limiting module, which can limit the number of visits of an IP in a unit time. But there are still problems:
-
For example, many schools and companies now use the same export IP. If you press the IP restriction directly, you may mistakenly kill other normal users.
-
With so many VPNs, an attacker can switch VPNs after an IP is blocked to attack
Mobile phone verification
Isn't there a better way to guard against it? Of course. We can see that in recent years, almost all applications will enable users to bind mobile phones, one is the national real-name policy requirements, the second is that mobile phones basically and ID card, basically can represent a person's identity. So many security operations are based on mobile phone authentication, login is also possible.
-
When a user enters a password more than three times, the user is required to enter an authentication code (preferably using sliding authentication)
-
When a user enters a password more than 10 times, mobile authentication pops up, requiring the user to log in using both mobile authentication code and password authentication
Brush protection for mobile phone verification code is another problem. Don't expand it here. I will have time to talk about what we have done in brush protection for verification code in the future.
The pseudocode is as follows:
fail_count = get_from_redis(fail_username) if fail_count > 3: if captcha is None: return error('Authentication code required') check_captcha(captcha) if fail_count > 10: #More than 10 logins with Authentication Code and Password if dynamic_code is None: return error('Please enter your mobile phone verification code') if not validate_dynamic_code(username, dynamic_code): delete_dynamic_code(username) return error('Mobile Phone Authentication Code Error') success = do_login(username, password, dynamic_code) if not success: set_redis(fail_username, fail_count + 1)
Combining the above methods with the authentication mode of mobile phone authentication code, we can basically prevent a considerable number of malicious attackers. But no system is absolutely secure, and we can only increase the attack cost of an attacker as much as possible. You can choose the appropriate strategy according to the actual situation of your website.
Intermediate Attack?
What is a man-in-the-middle attack
Man-in-the-middle attack (abbreviated to MITM). Simply put, A and B acquire or modify the communication content of A and B by sniffing, intercepting, etc. during the communication process.
Lift a chestnut: Xiao Bai delivers a courier to Xiao Huang Fa. On the way, Xiao Hei passes by courier point A. He hides in courier point A, or simply opens a courier point B by himself to impersonate courier point A. Then secretly disassembled Xiao Bai's express to Xiao Huang to see what's inside. You can even leave Xiao Bai's express mail behind and pack a hair-like box for him to send.
That is, during the login process, if an attacker sniffs a login request from the client to the server, he can easily get the user's username and password.
HTTPS
The easiest and most effective way to guard against man-in-the-middle attacks is to replace HTTPS and modify all HTTPS requests in your site to enforce HTTPS.
Why can HTTPS guard against man-in-the-middle attacks?
HTTPS actually joins the SSL/TLS protocol between the HTTP and TCP protocols to ensure the secure transmission of data. Compared to HTTP, HTTPS has the following main features:
-
Content Encryption
-
Data Integrity
-
Authentication
Specific HTTPS principles are no longer extended here, you can Google your own
Encrypted Transport
In addition to HTTPS, we can manually encrypt sensitive data for transmission:
-
User names can be decrypted on the server side using asymmetric encryption on the client side
-
Passwords can be transmitted after the client has MD5 to prevent exposing the clear text of the password
Other
In addition to what we're talking about above, there are many other things to consider, such as:
-
Operations log, which is required for each login and sensitive operation of the user (including IP, device, etc.)
-
Abnormal operation or login alert, with the above operation log, we can do risk alerts based on the log, such as users can be alerted by SMS when logging in very login, changing password, or logging in abnormal.
-
Disallow weak passwords when registering or modifying passwords
-
Prevent user names from being traversed Some Web sites will prompt for the existence of user names after they have been entered for registration. There is a risk that all user names of the site will be compromised (traversing the interface is sufficient) and interactive or logical constraints will be required.
-
...
Postnote
Now the country is constantly promulgating various laws, which place more and more emphasis on users'data. As developers, we also need to do more to protect user data and user privacy. Later, I will also chat with you about what we have done in data security. I hope you can get some help.