项目开发中的安全问题怎么处理?

news2024/11/18 18:25:08

目录

1.客户的数据不可信

2. 客户端提交的参数需要校验

3.请求头里的内容出现错误


1.客户的数据不可信

@PostMapping("/order")
public void wrong(@RequestBody Order order) {
 this.createOrder(order);
}

 对应的实体类如下:

@Data
public class Order {
 private long itemId; //商品ID
 private BigDecimal itemPrice; //商品价格
 private int quantity; //商品数量
 private BigDecimal itemTotalPrice; //商品总价
}

这样的话,用户可能传过来的单价和总价有问题

服务端也一定要重新从数据库来初始化商品的价格,重新计算最终的订单价格。如果不这么做的话,很可能会被黑客利用,商品总价被恶意修改为比较低 的价格。

@PostMapping("/orderRight")
public void right(@RequestBody Order order) {
 //根据ID重新查询商品
 Item item = Db.getItem(order.getItemId());
 //客户端传入的和服务端查询到的商品单价不匹配的时候,给予友好提示
 if (!order.getItemPrice().equals(item.getItemPrice())) {
 throw new RuntimeException("您选购的商品价格有变化,请重新下单");
 }
 //重新设置商品单价
 order.setItemPrice(item.getItemPrice());
 //重新计算商品总价
 BigDecimal totalPrice = item.getItemPrice().multiply(BigDecimal.valueOf(order.getQuantity()));
 //客户端传入的和服务端查询到的商品总价不匹配的时候,给予友好提示
 if (order.getItemTotalPrice().compareTo(totalPrice)!=0) {
 throw new RuntimeException("您选购的商品总价有变化,请重新下单");
 }
 //重新设置商品总价
 order.setItemTotalPrice(totalPrice);
 createOrder(order);
}

        一种可行的做法是,让客户端仅传入需要的数据给服务端,像这样重新定义一个 POJO CreateOrderRequest 作为接口入参,比直接使用领域模型 Order 更合 理。在设计接口时,我们会思考哪些数据需要客户端提供,而不是把一个大而全的对象作为参数提供给服务端,以避免因为忘记在服务端重置客户端数据 而导致的安全问题。

推荐写法

@Data
public class CreateOrderRequest {
 private long itemId; //商品ID
 private int quantity; //商品数量
}
@PostMapping("orderRight2")
public Order right2(@RequestBody CreateOrderRequest createOrderRequest) {
 //商品ID和商品数量是可信的没问题,其他数据需要由服务端计算
 Item item = Db.getItem(createOrderRequest.getItemId());
 Order order = new Order();
 order.setItemPrice(item.getItemPrice());
 order.setItemTotalPrice(item.getItemPrice().multiply(BigDecimal.valueOf(order.getQuantity())));
 createOrder(order);
 return order;
}

2. 客户端提交的参数需要校验

@Slf4j
@RequestMapping("trustclientdata")
@Controller
public class TrustClientDataController {
 //所有支持的国家
 private HashMap<Integer, Country> allCountries = new HashMap<>();
 public TrustClientDataController() {
 allCountries.put(1, new Country(1, "China"));
 allCountries.put(2, new Country(2, "US"));
 allCountries.put(3, new Country(3, "UK"));
 allCountries.put(4, new Country(4, "Japan"));
 }
 @GetMapping("/")
 public String index(ModelMap modelMap) {
 List<Country> countries = new ArrayList<>();
 //从数据库查出ID<4的三个国家作为白名单在页面显示
 countries.addAll(allCountries.values().stream().filter(country -> country.getId()<4).collect(Collectors.toList()));
 modelMap.addAttribute("countries", countries);
 return "index";
 }
} 

 html写法

...
<form id="myForm" method="post" th:action="@{/trustclientdata/wrong}">
 <select id="countryId" name="countryId">
 <option value="0">Select country</option>
 <option th:each="country : ${countries}" th:text="${country.name}" th:value="${country.id}"></option>
 </select>
 <button th:text="Register" type="submit"/>
</form>
..

 以上的参数只有三个,假如有以下的方法:

@PostMapping("/wrong")

@ResponseBody

public String wrong(@RequestParam("countryId") int countryId) {

 return allCountries.get(countryId).getName();

}

如何我在访问的时候直接发送以下请求

curl http://localhost:45678/trustclientdata/wrong\?countryId=4 -X POST

那么肯定会系统报错

解决办法:

@PostMapping("/right")
@ResponseBody
public String right(@RequestParam("countryId") int countryId) {
 if (countryId < 1 || countryId > 3)
 throw new RuntimeException("非法参数");

 return allCountries.get(countryId).getName();

}

或者使用spring validation

@Validated

public class TrustClientParameterController {

 @PostMapping("/better")
 @ResponseBody
 public String better(

 @RequestParam("countryId")

 @Min(value = 1, message = "非法参数")

 @Max(value = 3, message = "非法参数") int countryId) {
 return allCountries.get(countryId).getName();
 }
}

客户端提交的参数需要校验的问题,可以引申出一个更容易忽略的点是,我们可能会把一些服务端的数据暂存在网页的隐藏域中,这样下次页面提交的时 候可以把相关数据再传给服务端。虽然用户通过网页界面的操作无法修改这些数据,但这些数据对于 HTTP 请求来说就是普通数据,完全可以随时修改为 任意值。所以,服务端在使用这些数据的时候,也同样要特别小心。

3.请求头里的内容出现错误

@Slf4j

@RequestMapping("trustclientip")

@RestController

public class TrustClientIpController {
 HashSet<String> activityLimit = new HashSet<>();
 @GetMapping("test")
 public String test(HttpServletRequest request) {
 String ip = getClientIp(request);
 if (activityLimit.contains(ip)) {
 return "您已经领取过奖品";
 } else {

 activityLimit.add(ip);

 return "奖品领取成功";
 }
 }
 private String getClientIp(HttpServletRequest request) {
 String xff = request.getHeader("X-Forwarded-For");
 if (xff == null) {
 return request.getRemoteAddr();
 } else {
 return xff.contains(",") ? xff.split(",")[0] : xff;

 }

 }

}

通过一个 HashSet 模拟已发放过奖品的 IP 名单,每次领取奖品后把 IP 地址加入这个名单中。IP 地址的获取方式是:优先通过 X-Forwarded-For 请求头来获 取,如果没有的话再通过 HttpServletRequest 的 getRemoteAddr 方法来获取。通常我们的应用之前都部署了反向代理或负载均衡器,remoteAddr 获得的只 能是代理的 IP 地址,而不是访问用户实际的 IP。这不符合我们的需求,因为反向代理在转发请求时,通常会把用户真实 IP 放入 X-Forwarded-For 这个请求 头中。这种过于依赖 X-Forwarded-For 请求头来判断用户唯一性的实现方式,是有问题的。

比如我们可以通过模拟发送下面的请求头信息来影响业务:

curl http://localhost:45678/trustclientip/test -H "X-Forwarded-For:183.84.18.71, 10.253.15.1"

因此,IP 地址或者说请求头里的任何信息,包括 Cookie 中的信息、Referer,只能用作参考,不能用作重要逻辑判断的依据。而对于类似这个案例唯一性的 判断需求,更好的做法是,让用户进行登录或三方授权登录(比如微信),拿到用户标识来做唯一性判断

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/691984.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[框架]MyBatis框架

关于MyBatis框架 MyBatis框架的主要作用&#xff1a;实现并简化数据库编程。 MyBatis框架的依赖项 MyBatis框架的依赖项是&#xff1a;mybatis&#xff0c;但&#xff0c;通常还应该再添加&#xff1a;mybatis-spring、spring-jdbc、mysql或其它数据库的依赖项、数据库连接池…

FreeRTOS_列表和列表项

目录 1. 什么是列表和列表项&#xff1f; 1.1 列表 1.2 列表项 1.3 迷你列表项 2. 列表和列表项初始化 2.1 列表初始化 2.2 列表项初始化 3. 列表项插入 3.1 列表项插入函数分析 3.2 列表项插入过程图示 3.2.1 插入值为 40 的列表项 3.2.2 插入值为 60 的列表项 3…

c++ while(i--) 的执行顺序

问&#xff1a;while (i--) {语句B} 的执行顺序是什么&#xff1f; 首先执行i--,再执行 while ,再执行语言B. 一个案例&#xff1a; 案例中count 的初始值为-3. 第一个打出的为-2&#xff0c; 证明的之前的判断流程。 附录&#xff1a; while(条件){//语句A} 的执行逻辑&…

聊聊PCIe协议的BDF

[摘要]&#xff1a;本文主要介绍 PCIe 协议中 Bus、Device 和 Function 的基本定义。 PCIe 总线的拓扑结构就像一颗葡萄树&#xff1a;树根相当于 PCIe Root Complex&#xff0c;树干和树枝相当于 PCIe Bus&#xff0c;一整串葡萄相当于 PCIe Device&#xff0c;一颗葡萄相当于…

c++构造基类

c构造基类 c构造基类采用初始化列表 基类的成员变量由基类的构造函数初始化 派生类的成员变量由派生类的构造函数初始化 基类&#xff1a; 派生类: 调用

微信扫码对接

微信扫码对接&#xff0c;如果刚开始没有资源进行对接。 可以选择先申请微信公众测试平台进行测试&#xff0c;地址如下 微信公众平台 申请步骤等等简单的就不说了&#xff0c;本文主要说一下需要注意的坑。 1.首先需要一个外网地址&#xff0c;做本地映射&#xff0c;否则…

掌握这些容易被忽略的Vue组件细节,提升开发效率,事半功倍!

组件允许我们将 UI 划分为独立的、可重用的部分&#xff0c;并且可以对每个部分进行单独的思考。 组件在日常开发的重要性不言而喻&#xff0c;掌握下述细则&#xff0c;可以让你在开发中事半功倍&#xff01; Props defineProps() 宏中的参数不可以访问 <script setup&…

mysql的高可用架构之mmm

目录 一、mmm的相关知识 1&#xff09;mmm架构的概念 2&#xff09;MMM 高可用架构的重要组件 3&#xff09;mmm故障切换流程 二、mmm高可用双主双从架构部署 实验设计 实验需求 实验组件部署 具体实验步骤 步骤一&#xff1a; 搭建 MySQL 多主多从模式 &#…

Uniapp中简单弹出层的使用

图示 思路 当派工单这个输入框获取到焦点后&#xff0c;弹出弹出层选择数据。 1、定义这个输入框 <view class"cu-form-group"><view class"title"><text class"text-red">*</text>派工单号: </view><input…

Mysql查询语句优化方法

查询优化 小表驱动大表 优化原则&#xff1a;对于MySQL数据库而言&#xff0c;永远都是小表驱动大表。 /** * 举个例子&#xff1a;可以使用嵌套的for循环来理解小表驱动大表。 * 以下两个循环结果都是一样的&#xff0c;但是对于MySQL来说不一样&#xff0c; * 第一种可以理解…

第1章-Java语言概述

Java基础知识图解 1. Java语言概述 1.1 Java简史 是SUN(Stanford University Network&#xff0c;斯坦福大学网络公司 ) 1995年推出的一门高级编程语言。是一种面向Internet的编程语言。 Java一开始富有吸引力是因为Java程序可以在Web浏览器中运行。 这些Java程序被称为Java小…

DepthAI API详解

目录 DepthAI的整体架构Device 对象通过标识连接到指定设备定义输入/输出队列Device对象的常用方法addLogCallback()方法close()方法getInputQueue()方法getOutputQueue()方法 PipelinePipeline常用的方法create()方法createColorCamera()方法createMonoCamera()方法createNeur…

泛微以低代码助力央企合规、案件管理数字化

近年来&#xff0c;国家出台一系列文件&#xff0c;不断强化央企国企合同、法务、合规、风控一体化管理&#xff0c;深化法治企业建设。 2022年&#xff0c;国资委印发《中央企业合规管理办法》&#xff0c;要求中央企业加强合规管理&#xff0c;切实防控风险&#xff0c;并指…

新手小白学JAVA_IDEA修改主题 设置背景图片

很多小白在刚刚使用IDEA的时候还不是很熟练 本文主要给大家提供一些使用的小技巧&#xff0c;希望能帮助到你 1.修改IDEA默认主题 IDEA的默认主题是黑色的&#xff0c;其实也可以选择其他的主题 我们一起来试一试吧~ 2.修改IDEA背景图片 IDEA的背景图片也是可以自定义的 我们…

arcgis波段提取--多波段合成

1、打开软件&#xff0c;导入彩色栅格影像&#xff0c;如下&#xff1a; 上图有RGB三个波段&#xff0c;在左侧图层下可以看到波段情况。 2、在菜单栏中选择"窗口"--"影像分析"&#xff0c;如下&#xff1a; 点击影像分析功能&#xff0c;打开如下界面&am…

移除flyway,手动进行数据库的迁移

国产数据库如达梦、金仓数据库&#xff0c;开源数据迁移工具貌似支持的很少&#xff0c;手写工具类进行数据库脚本的迁移&#xff0c;主要有2个类如下&#xff1a; /*** 模拟flyway进行sql迁移*/ Component Slf4j public class SqlInitialize implements InitializingBean, Ord…

Java【String字符串不可变】

字符串不可变&练习 字符串不可变1. 字符串设置为不可变的原因2. 如何修改字符串内容3 StringBuilder类的具体使用4. 面试题 字符串不可变 1. 字符串设置为不可变的原因 方便实现字符串常量池&#xff0c;若String对象可变&#xff0c;常量池中的内容就会随时变化&#xf…

Linux SVN提交日志校验

#!/bin/bash export LANG"en_US.UTF-8" #确保中文日志显示正常&#xff0c;便于统计日志 REPOS"$1" TXN"$2" #限制日志长度 LENGTH20 #exit 0SVNLOOK"/usr/bin/svnlook" BLACKLIST".* *.o *.chw *.pck ~\$*"function error_…

五、菜单管理

云尚办公系统&#xff1a;菜单管理 B站直达【为尚硅谷点赞】: https://www.bilibili.com/video/BV1Ya411S7aT 本博文以课程相关为主发布&#xff0c;并且融入了自己的一些看法以及对学习过程中遇见的问题给出相关的解决方法。一起学习一起进步&#xff01;&#xff01;&#x…

【Linux系统编程】Linux基本指令详解(二)

文章目录 前言1. cp 指令&#xff08;重要&#xff09;2. mv 指令&#xff08;重要&#xff09;3. cat 指令echo 命令输出重定向追加重定向wc 命令输入重定向 4. more 指令5. less指令&#xff08;重要&#xff09;6. head指令7. tail指令8. 命令行管道&#xff08;了解&#x…