What is horizontal/vertical overstepping?
Horizontal Override: Horizontal override refers to an attacker attempting to access resources of a user with the same privileges as he has.
Vertical Override: Vertical override refers to a low-level attacker attempting to access resources of high-level users.
How can I prevent the lateral overstepping loophole?
By establishing a binding relationship between a user and an operational resource, a user can ensure that the resource is owned by that user when operating on any resource.Indirectly map the key parameters in the request to avoid using the original key parameter names, such as index 1 instead of id value 123, etc.
How to prevent vertical override vulnerability?
*It is recommended to use role-based access control mechanisms to prevent vertical override attacks, that is, to pre-define different privilege roles, assign different privileges to each role, and each user belongs to a specific role, that is, to have fixed privileges. When a user performs an action or produces an action, the user's role is used to determine whether the action or action is allowed.
Functional Scenarios
E-commerce projects have the functions of adding addresses, deleting addresses, modifying addresses, updating addresses and so on in the receiving address module. When implementing the functions of deleting/updating/querying addresses, there will be potential security risks of exceeding the authority horizontally. When landing, our users are the logged-in general user accounts, preventing some hackers or illegal elements from passing one after landing.Not his own shippingId, then he can tamper with our information at will, making information leak and other hidden dangers, such as:
ShippingServiceImpl.java
public ServerResponse<String> delete(Integer userId, Integer shippingId) { //Call Mybatis's deleteByPrimaryKey() method directly int rowCount = shippingMapper.deleteByPrimaryKey(shippingId); if (rowCount > 0) { return ServerResponse.createBySuccessMessage("Address Deleted Successfully"); } return ServerResponse.createByErrorMessage("Failed to delete address"); }
If deleteByPrimaryKey() is used directly to delete an address when deleting the Receipt Address function is implemented, there will be the potential for lateral override of authority. It should also be called by the hacker to delete this interface. To solve this problem, we must customize a new deletion method to bind to the operational resources of our landing users to achieveDelete address:
@Override public ServerResponse<String> delete(Integer userId, Integer shippingId) { //To prevent the horizontal override method from being unavailable, you do not need to define the deleteByUserIdShippingId() method to implement the deletion // int rowCount = shippingMapper.deleteByPrimaryKey(shippingId); int rowCount = shippingMapper.deleteByUserIdShippingId(userId, shippingId); if (rowCount > 0) { return ServerResponse.createBySuccessMessage("Address Deleted Successfully"); } return ServerResponse.createByErrorMessage("Failed to delete address"); }
At this time, deleting the address requires passing a userId parameter, so it can avoid the illegal elements to delete directly!The dao layer works as follows:
int deleteByUserIdShippingId(@Param("userId")Integer userId,@Param("shippingId") Integer shippingId);
When the address update function is implemented, there is also a security risk of crossing the authority horizontally:
@Override public ServerResponse update(Integer userId, Shipping shipping) { //Re-assign userId shipping.setUserId(userId); /** * UserId is reassigned using the landing shipping, why do you need to reassign it??? Because the userId of shipping can also be simulated. * If you don't take it from the logged-in user and use the userId directly, it will also update the person's address, then there is still a problem of exceeding authority, all of which need to be reassigned. */ int rowCount = shippingMapper.updateByShipping(shipping); if (rowCount > 0) { return ServerResponse.createBySuccessMessage("Address information updated successfully"); } return ServerResponse.createByErrorMessage("Failed to update address information"); }
Why re-assign userId here?Since the userId of shipping can also be simulated, if it is not taken from the landing user, the userId passed in will be used directly, which will also update the address of the person, then there is still an override problem, all of which need to be reassigned.
We also need to redefine an update method to bind the user's operational resources to the user as follows:
ShippingMapper and ShippingMapper.xml
int updateByShipping(Shipping shipping);
<update id="updateByShipping" parameterType="com.lbz.entity.Shipping"> update tb_shipping set receiver_name = #{receiverName,jdbcType=VARCHAR}, receiver_phone = #{receiverPhone,jdbcType=VARCHAR}, receiver_province = #{receiverProvince,jdbcType=VARCHAR}, receiver_city = #{receiverCity,jdbcType=VARCHAR}, receiver_district = #{receiverDistrict,jdbcType=VARCHAR}, receiver_address = #{receiverAddress,jdbcType=VARCHAR}, zip_code = #{zipCode,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=TIMESTAMP}, update_time = now() where id = #{id,jdbcType=INTEGER} --Appoint user_id For the current user id and user_id = #{userId,jdbcType=INTEGER} </update>