Today’s security quick tip is brought to you by some API penetration tests I’ve completed over the past few weeks. One of the things I’ve noticed more and more as organizations are developing and implementing APIs as part of their overall application infrastructure is the presence of “greedy” or overly verbose JSON objects in HTTP responses. With this problem comes an abundance of sensitive data, such as password hashes, returned from the database to the client. Even if the data in the returned object isn’t used in the user interface, any client with an intercepting proxy can view the contents of those responses. Instead of returning unnecessary data, leave passwords and other sensitive information in the database where they belong.
Why is This a Problem?
While it should be pretty obvious in this case, I always like to start out addressing the real issue in a vulnerability/exploit. When unnecessary information is returned in responses from your web application or API, an attacker can use that unnecessary information to launch other attacks, gather sensitive information about other clients/users, or fingerprint the underlying application infrastructure. One of the worst case scenarios here is when responses contain passwords (hopefully hashed). Any user able to execute this request and view the response could take those passwords offline, attempt to crack them, and then use them to gain unauthorized access to other user accounts, moving laterally or potentially escalating their privileges.
Even administrative accounts shouldn’t be able to see sensitive information like password hashes in HTTP responses, as it could allow them to recover other user credentials. These credentials could be shared with other systems or a malicious insider could use the credentials to imitate another user. Another example of potentially unnecessary information returned would be usernames for other users, when authenticated as a low-privileged account. This could give an attacker targets for privilege escalation attempts.
How Should You Fix It?
Don’t return sensitive information. Alright, we’re done here. Probably more useful than the obvious here though is to implement some secure coding training and peer reviews that keep an eye out for this kind of thing. All responses should include specific data fields that are required by the front-end, rather than “select *” approaches. Fields like passwords should never be returned as part of a response. Also, mitigating controls are useful here, like double-checking the hashing algorithm you are using for storing passwords to make sure it is strong, has a high work factor to increase resistance to password attacks (e.g. bcrypt), and leverages salting.
The moral of the story here is to pay attention to what kinds of things you are sending from server to client as part of your application and API architecture. The principle of least privilege should certainly apply here and things like passwords should be left in the database where they belong!