当前位置: 首页 > backend >正文

Java开发经验——阿里巴巴编码规范实践解析5

摘要

这篇文章主要介绍了阿里巴巴Java开发规范中关于安全和性能优化的实践解析。内容涵盖了配置文件密码加密、用户输入内容风控、SQL注入防护、参数有效性验证、XSS攻击防护、CSRF安全验证、文件上传安全检查、防重放机制等多个方面,通过正反示例和推荐做法,为Java开发者提供了详细的安全开发指导。

1. 【强制】隶属于用户个人的页面或者功能必须进行权限控制校验。

说明:防止没有做水平权限校验就可随意访问、修改、删除别人的数据,比如查看他人的私信内容。

这是一个涉及系统安全和用户隐私保护的强制性安全规范

1.1. 什么是水平权限校验?

水平权限控制是指:同一角色的用户只能访问属于自己权限范围的数据

例如:用户 A 登录系统后,只能访问自己的订单、地址、消息等;不能看到或操作用户 B 的内容。

1.2. 为什么必须校验?

如果不做水平权限控制:

  • 用户 A 可以通过修改 URL 参数或请求体中的 userId=123 来访问或修改 用户 B 的数据;
  • 这是严重的越权访问漏洞,可能导致信息泄露、数据篡改,甚至被黑产利用。

1.3. ✅ 正例(正确做法)

以 Spring Boot + MyBatis 为例,查询用户订单时加上当前登录用户 ID:

// Controller
@GetMapping("/order/{orderId}")
public Order getOrder(@PathVariable Long orderId, @AuthenticationPrincipal UserDetails user) {Long userId = Long.parseLong(user.getUsername());return orderService.getOrderForUser(orderId, userId);
}// Service
public Order getOrderForUser(Long orderId, Long userId) {Order order = orderMapper.findByIdAndUserId(orderId, userId);if (order == null) {throw new BusinessException("无权访问该订单");}return order;
}

数据库 SQL 示例(MyBatis):

SELECT * FROM orders WHERE id = #{orderId} AND user_id = #{userId}

1.4. ❌ 反例(错误做法)

// 未验证 userId 是否为当前登录用户
public Order getOrder(Long orderId) {return orderMapper.findById(orderId); // 任何用户可访问任意订单
}

1.5. ✅ 推荐校验方法

场景

校验方式

URL 中含 userId、orderId 等

使用登录用户的 ID 与传参比对,或直接从 Token 中获取

查询/删除数据库记录

SQL 中加上 user_id = 当前用户ID

操作数据表单

后端验证该数据是否属于当前用户

接口返回列表

查询条件中加上用户 ID 限制

2. 【强制】用户敏感数据禁止直接展示,必须对展示数据进行脱敏。

正例:中国大陆个人手机号码显示:139****1219,隐藏中间 4 位,防止隐私泄露。

2.1. ✅ 正例代码示例

User user = getUser();// 脱敏处理
String maskedPhone = DesensitizationUtil.maskPhone(user.getPhone());
String maskedIdCard = DesensitizationUtil.maskIdCard(user.getIdCard());logger.info("用户信息 - userId: {}, phone: {}, idCard: {}", user.getId(), maskedPhone, maskedIdCard);

推荐在日志中使用 userIdorderIduuid 等非敏感的唯一标识进行问题定位。

2.2. ❌ 反例代码(绝对禁止)

java复制编辑
logger.info("用户信息 - 姓名: {}, 身份证: {}, 手机号: {}", user.getName(), user.getIdCard(), user.getPhone());
// 泄露完整敏感信息,严重违规

2.3. ✅ 推荐脱敏工具类 DesensitizationUtil

public class DesensitizationUtil {public static String maskPhone(String phone) {if (phone == null || phone.length() != 11) return phone;return phone.substring(0, 3) + "****" + phone.substring(7);}public static String maskIdCard(String idCard) {if (idCard == null || idCard.length() < 8) return idCard;return idCard.substring(0, 3) + "***********" + idCard.substring(idCard.length() - 4);}public static String maskName(String name) {if (name == null || name.length() < 2) return "*";return name.charAt(0) + "*".repeat(name.length() - 1);}
}

3. 【强制】用户输入的 SQL 参数严格使用参数绑定或者 METADATA 字段值限定,防止 SQL 注入,禁止字符串拼接 SQL 访问数据库。

反例:某系统签名大量被恶意修改,即是因为对于危险字符#--没有进行转义,导致数据库更新时,where 后边的信息被注释掉,对全库进行更新。

3.1. 什么是 SQL 注入?

SQL 注入是指:攻击者通过构造恶意 SQL 片段注入到应用程序的参数中,最终执行了非预期的数据库操作。

例如,攻击者输入:

1 OR 1=1

可能变成:

SELECT * FROM users WHERE id = 1 OR 1=1

这样会返回所有用户,甚至更严重。

3.2. 为什么不能拼接 SQL?

  • 字符串拼接 SQL 是最常见的安全漏洞;
  • 没有过滤 --;'"or 等关键词,会导致注入;
  • 攻击者可以:
    • 绕过登录;
    • 窃取数据;
    • 删除表结构;
    • 执行后台命令(部分数据库支持);

3.3. ❌ 反例(错误示范)

// 错误示例:拼接 SQL 字符串(极其危险)
String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);

如果用户输入:

username: admin' -- 
password: xxx

SQL 变为:

SELECT * FROM users WHERE username = 'admin' -- ' AND password = 'xxx'

-- 将后半部分注释掉,绕过密码校验,直接登录。

3.4. ✅ 正例(参数绑定)

3.4.1. 使用 PreparedStatement(JDBC):

String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();

3.4.2. 使用 MyBatis:

<select id="getUserByUsernameAndPassword" resultType="User">SELECT * FROM users WHERE username = #{username} AND password = #{password}
</select>

MyBatis 会自动使用 PreparedStatement 参数绑定,防止注入。

3.5. ❗️元数据字段限制(METADATA字段约束)

在某些系统中,还可以通过字段白名单、枚举映射来限制参数取值:

// 限定只允许操作指定字段
List<String> allowedFields = Arrays.asList("name", "email", "phone");
if (!allowedFields.contains(inputField)) {throw new IllegalArgumentException("非法字段参数");
}

4. 【强制】用户请求传入的任何参数必须做有效性验证。

说明:忽略参数校验可能导致:

  • 页面 page size 过大导致内存溢出
  • 恶意 order by 导致数据库慢查询
  • 缓存击穿
  • SSRF
  • 任意重定向
  • SQL 注入, Shell 注入, 反序列化注入
  • 正则输入源串拒绝服务 ReDoS

扩展: Java 代码用正则来验证客户端的输入,有些正则写法验证普通用户输入没有问题,但是如果攻击人员使

用的是特殊构造的字符串来验证,有可能导致死循环的结果。

所有用户传入的参数(URL、Header、Body、Query 等)都必须进行有效性验证,否则可能被恶意利用,造成安全漏洞或系统稳定性问题。

4.1. 不校验参数的后果

问题类型

举例说明

内存溢出

用户传入 pageSize=1000000,系统一次性加载百万数据,直接 OOM

数据库慢查询

用户传入 orderBy=name or 1=1,造成索引失效,扫描全表

缓存击穿

用户不断请求不存在的数据 ID,频繁绕过缓存,打到数据库

SSRF(服务端请求伪造)

用户传入图片 URL 为 http://127.0.0.1:8080/admin/deleteAll,诱导服务器内网请求内部服务

任意重定向

用户传入 redirectUrl=恶意网站,跳转诱导点击

SQL注入 / Shell注入 / 反序列化注入

拼接参数时未校验引号、分号、命令符等危险字符

ReDoS(正则拒绝服务)

用户传入字符串导致 Java 正则表达式陷入指数型回溯,CPU 满载

4.2. ❌ 反例(没有参数校验)

@GetMapping("/search")
public List<User> search(String keyword, Integer pageSize) {// 用户传入 keyword = ".*(a+)+.*" pageSize = 1000000List<User> users = userService.search(keyword, pageSize); return users;
}

问题:

  • 正则 ReDoS;
  • pageSize 太大导致内存泄漏;
  • keyword 可能造成数据库慢查或注入。

4.3. ✅ 正例(有效参数校验)

@GetMapping("/search")
public List<User> search(@RequestParam @Size(max = 100) String keyword,@RequestParam(defaultValue = "10") @Min(1) @Max(100) Integer pageSize) {if (!Pattern.matches("[a-zA-Z0-9]+", keyword)) {throw new IllegalArgumentException("非法关键字");}return userService.search(keyword, pageSize);
}

4.4. 📌 校验建议分类

类型

校验方式

文本

长度、正则、白名单

数字

最大/最小值限制,分页页码控制

列表

限定最大长度,内容去重

枚举

检查是否是定义好的值

文件

限定大小、类型(MIME)

URL

限定白名单前缀,不能是本地地址

重定向

使用服务端安全跳转逻辑,避免直接 redirect 用户输入地址

4.5. 🔐 安全推荐

  1. 使用 JSR-303(如 @Valid@NotNull@Size 等注解)+ 全局异常处理;
  2. 所有 order bygroup by 字段都使用白名单校验;
  3. 对上传的 URL / 文件内容做严格限制(防止 SSRF / 木马);
  4. 参数校验统一抽象在服务层或工具类,保持一致性;
  5. 对于外部调用(第三方接口)输入输出也要加参数验证。

4.6. 示例工具组合推荐:

框架/工具

用途

@Validated+ @Valid + JSR-303

Spring Boot 参数校验

Pattern.matches()+ 正则白名单

字符串内容检查

commons-validator

URL、邮箱、IP 等验证

Guava RateLimiter

限流防刷

spring-security-example/
├── controller/
│   └── UserController.java
├── dto/
│   └── UserRegisterDTO.java
├── validator/
│   └── EmailValidator.java
├── config/
│   └── RateLimiterConfig.java
├── rate/
│   └── RateLimitAspect.java
├── annotation/
│   └── RateLimited.java

4.6.1. 核心依赖(pom.xml

<dependencies><!-- 参数校验 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><!-- commons-validator --><dependency><groupId>commons-validator</groupId><artifactId>commons-validator</artifactId><version>1.7</version></dependency><!-- Guava RateLimiter --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.0.1-jre</version></dependency><!-- AOP 支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
</dependencies>

4.6.2. ✅ DTO 参数验证示例(UserRegisterDTO.java)

@Data
public class UserRegisterDTO {@NotBlank(message = "用户名不能为空")private String username;@NotBlank(message = "密码不能为空")@Size(min = 8, max = 20, message = "密码长度必须在8-20之间")private String password;@Email(message = "邮箱格式不正确")private String email;@Pattern(regexp = "^[0-9]{6}$", message = "验证码必须是6位数字")private String verifyCode;
}

4.6.3. ✅ Controller 示例(UserController.java)

@RestController
@RequestMapping("/api/user")
@Validated
public class UserController {@PostMapping("/register")@RateLimitedpublic String register(@Valid @RequestBody UserRegisterDTO dto) {return "注册成功";}
}

4.6.4. ✅ Guava 限流(RateLimiterConfig.java)

@Configuration
public class RateLimiterConfig {@Beanpublic RateLimiter rateLimiter() {// 每秒最多允许 5 个请求return RateLimiter.create(5.0);}
}

4.6.5. ✅ 限流注解 + AOP 拦截(RateLimited.java + RateLimitAspect.java)

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimited {
}
@Aspect
@Component
public class RateLimitAspect {@Autowiredprivate RateLimiter rateLimiter;@Around("@annotation(com.example.annotation.RateLimited)")public Object limit(ProceedingJoinPoint pjp) throws Throwable {if (!rateLimiter.tryAcquire()) {throw new RuntimeException("请求过于频繁,请稍后再试");}return pjp.proceed();}
}

4.6.6. ✅ 使用 commons-validator 检查邮箱(可扩展)

public class EmailValidatorUtil {public static boolean isValidEmail(String email) {return org.apache.commons.validator.routines.EmailValidator.getInstance().isValid(email);}
}

4.6.7. 🧪 示例异常返回格式(统一处理)

@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<String> handleValidException(MethodArgumentNotValidException e) {return ResponseEntity.badRequest().body(e.getBindingResult().getFieldError().getDefaultMessage());}@ExceptionHandler(Exception.class)public ResponseEntity<String> handle(Exception e) {return ResponseEntity.status(500).body("服务器错误: " + e.getMessage());}
}

5. 【强制】禁止向 HTML 页面输出未经安全过滤或未正确转义的用户数据。

说明: XSS 跨站脚本攻击。它指的是恶意攻击者往 Web 页面里插入恶意 html 代码,当用户浏览时,嵌入其中 Web 里面的 html 代码会被执行,造成获取用户 cookie、钓鱼、获取用户页面数据、蠕虫、挂马等危害。

禁止向 HTML 页面输出未经安全过滤或未正确转义的用户数据,目的是防止 XSS(Cross Site Scripting)跨站脚本攻击

XSS 攻击原理:攻击者通过在输入中插入恶意脚本(如 <script> 标签、onerror 属性等),使其在其他用户浏览网页时被浏览器执行,进而执行恶意操作,例如:

  • 窃取用户 cookie;
  • 执行钓鱼攻击;
  • 操作 DOM 页面;
  • 利用浏览器漏洞传播蠕虫病毒。

5.1. 🚨 危险示例(XSS 攻击演示):

场景:在页面显示用户昵称

后端代码:

// 用户昵称从请求中读取,未做处理直接输出
String nickname = request.getParameter("nickname");
out.println("<div>欢迎你," + nickname + "</div>");

攻击请求:

http://example.com/page?nickname=<script>alert('XSS')</script>

最终页面渲染结果:

<div>欢迎你,<script>alert('XSS')</script></div>

✅ 结果:用户打开页面时,脚本被执行,弹出 alert。

5.2. ✅ 安全做法(防止 XSS):

对输出进行 HTML 转义

将特殊字符进行转义,如:

  • <&lt;
  • >&gt;
  • "&quot;
  • '&#x27;
  • &&amp;

后端 Java 处理:

String nickname = StringEscapeUtils.escapeHtml4(request.getParameter("nickname"));
out.println("<div>欢迎你," + nickname + "</div>");

使用 Apache Commons Text 的:

import org.apache.commons.text.StringEscapeUtils;

结果页面:

<div>欢迎你,&lt;script&gt;alert('XSS')&lt;/script&gt;</div>

浏览器只会显示这段文本,不会执行脚本。

使用模板引擎自动转义

如 Thymeleaf、FreeMarker 等模板引擎通常默认输出会自动转义。

Thymeleaf 示例:

<p th:text="${nickname}">昵称</p> <!-- 自动 HTML 转义 -->

设置 CSP(Content Security Policy)

通过 HTTP 响应头限制页面执行外部或内联脚本,如:

Content-Security-Policy: script-src 'self'

6. 【强制】表单、AJAX 提交必须执行 CSRF 安全验证。

说明: CSRF (Cross-site request forgery) 跨站请求伪造是一类常见编程漏洞。 对于存在 CSRF 漏洞的应用/网站,攻击者可以事先构造好 URL,只要受害者用户一访问,后台便在用户不知情的情况下对数据库中用户参数进行相应修改。

7. 【强制】URL 外部重定向传入的目标地址必须执行白名单过滤。

说明: 攻击者通过恶意构造跳转的链接,可以向受害者发起钓鱼攻击。

8. 【强制】在使用平台资源, 譬如短信、 邮件、 电话、 下单、 支付, 必须实现正确的防重放的机制,如数量限制、疲劳度控制、验证码校验,避免被滥刷而导致资损。

说明:如注册时发送验证码到手机,如果没有限制次数和频率,那么可以利用此功能骚扰到其它用户,并造成短信平台资源浪费。

8.1. 规则内容:

使用平台资源(短信、邮件、电话、下单、支付等)必须实现防重放机制,避免被滥刷。

8.2. ⚠️ 背后风险:

风险场景

风险后果

注册接口无限制发短信

骚扰他人,短信平台费用急剧上升

邮件接口无限制发验证码

被滥用为发垃圾邮件平台,系统被封域名/IP

支付或下单接口可重复提交

重复扣款、资损、库存异常

滑动验证、验证码绕过

恶意注册、批量盗号、接口刷爆

8.3. ❌ 错误做法(无限制发送短信验证码)

@PostMapping("/sendSms")
public ResponseEntity<String> sendSms(@RequestParam String phone) {smsService.sendVerificationCode(phone);return ResponseEntity.ok("验证码已发送");
}
  • ❌ 没有限制调用频率;
  • ❌ 没有疲劳度判断(如1分钟内连续请求);
  • ❌ 没有验证码/Token机制防重放;
  • ✅ 攻击者可短时间请求几千次,造成严重资损。

8.4. ✅ 正确示例(多重防护)

@PostMapping("/sendSms")
public ResponseEntity<String> sendSms(@RequestParam String phone, HttpServletRequest request) {
String ip = request.getRemoteAddr();// 1. 限频防刷(基于IP+手机号)
if (!rateLimiter.tryAcquire(ip + ":" + phone)) {return ResponseEntity.status(429).body("发送频繁,请稍后再试");
}// 2. 疲劳度控制(每小时最多发送3次)
if (smsService.countToday(phone) >= 3) {return ResponseEntity.badRequest().body("发送次数过多");
}// 3. 验证码校验机制(如图形验证码、行为验证)
if (!captchaService.verify(request)) {return ResponseEntity.badRequest().body("图形验证码错误");
}// 4. 加入 Token 防重放(可选)
String requestToken = request.getHeader("X-Request-Token");
if (tokenService.isReplay(requestToken)) {return ResponseEntity.status(403).body("请求重复,请刷新页面重试");
}// 执行发送
smsService.sendVerificationCode(phone);
return ResponseEntity.ok("验证码发送成功");
}

8.5. ✅ 建议防重放措施汇总

类型

说明

✅ 接口限频

Guava RateLimiter / Redis + Lua 限流脚本

✅ 疲劳度控制

每个手机号/IP 每小时最多几次,避免持续骚扰

✅ 图形验证码

有效防止机器自动请求

✅ 滑动验证码

腾讯云、极验等行为验证

✅ Token 防重放

前端生成一次性 token,请求后立即失效

✅ 请求签名校验

常用于支付等敏感接口,防止参数被篡改

9. 【强制】对于文件上传功能,需要对于文件大小、类型进行严格检查和控制。

说明:攻击者可以利用上传漏洞,上传恶意文件到服务器,并且远程执行,达到控制网站服务器的目的。这条规则是Web 安全中的核心防护要求之一,特别是应对文件上传攻击(File Upload Attack)

9.1. 规则内容:

文件上传功能必须对文件大小、类型进行严格检查和控制

9.2. ⚠️ 背后风险:

攻击者可能上传以下恶意文件:

文件类型

危害

.jsp.php.aspx

一旦被服务器执行,可远程控制服务器(WebShell)

.exe.bat

本地下载后诱导用户执行

.zip

Zip 炸弹攻击,占用系统资源

超大文件

消耗服务器带宽和磁盘资源,造成 DoS 攻击

文件伪装

.jpg 实为 .exe,混淆系统判断

9.3. ❌ 危险代码(未做检查)

@PostMapping("/upload")
public String uploadFile(@RequestParam MultipartFile file) throws IOException {
String fileName = file.getOriginalFilename();
File targetFile = new File("/upload/" + fileName);
file.transferTo(targetFile);
return "上传成功";
}
  • ❌ 没有限制文件大小;
  • ❌ 没有限制上传类型;
  • ❌ 直接保存在 Web 可访问目录;
  • ✅ 攻击者可上传 .jsp 文件并远程执行命令。

9.4. ✅ 安全示例(类型 + 大小校验)

@PostMapping("/upload")
public ResponseEntity<String> upload(@RequestParam MultipartFile file) throws IOException {// 1. 文件大小限制(最大5MB)if (file.getSize() > 5 * 1024 * 1024) {return ResponseEntity.badRequest().body("文件过大,限制为5MB以内");}// 2. 文件类型限制(只允许图片)String contentType = file.getContentType();List<String> allowedTypes = List.of("image/jpeg", "image/png", "image/gif");if (!allowedTypes.contains(contentType)) {return ResponseEntity.badRequest().body("仅支持上传 JPG/PNG/GIF 文件");}// 3. 校验文件后缀名(防伪装)String originalName = file.getOriginalFilename();if (originalName == null || !originalName.matches(".*\\.(jpg|jpeg|png|gif)$")) {return ResponseEntity.badRequest().body("文件扩展名非法");}// 4. 重命名 + 存储到非 web 目录String newFileName = UUID.randomUUID() + originalName.substring(originalName.lastIndexOf("."));File target = new File("/data/uploads/" + newFileName);file.transferTo(target);return ResponseEntity.ok("上传成功");
}

9.5. ✅ 安全增强建议

项目

建议

文件大小限制

上传接口应限制最大文件大小(如 5MB)

文件类型校验

使用 MIME 类型 + 文件扩展名双重校验

文件内容校验(可选)

对上传文件内容头进行 magic number 检查,防止伪装

上传路径隔离

不应保存在 Web 可访问路径下,如 /upload/xxx.jsp

文件重命名

使用 UUID、雪花ID 生成唯一文件名,避免路径穿越攻击

文件扫描

可选接入第三方病毒扫描(如 clamAV)

白名单机制

强烈推荐:只允许固定类型上传(白名单),拒绝其他

10. 【强制】配置文件中的密码需要加密。

10.1. 🚫 规则内容:

配置文件中的密码需要加密,不能明文写入,例如数据库、Redis、MQ、第三方服务的认证信息等。

10.2. ⚠️ 背后原因:

  1. 安全风险大:如果配置文件泄露,明文密码会直接暴露;
  2. 开发测试人员变动频繁,明文密码可能被滥用或传播;
  3. 合规要求:很多行业(如金融、政务)要求密码不能明文存储。

10.3. ❌ 错误示例(明文密码)

application.yml

spring:datasource:url: jdbc:mysql://localhost:3306/demousername: rootpassword: 123456   # ❌ 明文密码,存在泄露风险

10.4. ✅ 正确做法示例(加密 + 解密)

10.4.1. ✅ 使用加密工具对密码加密,启动时解密

10.4.1.1. 第一步:加密密码(使用 Jasypt)

命令加密(以 jasypt 为例):

java -cp jasypt.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI \input="123456" password="my-secret-key" algorithm=PBEWithMD5AndDES

输出加密结果如:

ENC(Rz5+1cREkP39EMuz0RVQPw==)
10.4.1.2. 第二步:配置文件中使用加密串
spring:datasource:url: jdbc:mysql://localhost:3306/demousername: rootpassword: ENC(Rz5+1cREkP39EMuz0RVQPw==)
10.4.1.3. 第三步:解密依赖

引入依赖:

<dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.4</version>
</dependency>

启动参数(传入密钥):

-Djasypt.encryptor.password=my-secret-key

10.4.2. ✅ 自己实现解密逻辑

custom:datasource:password: ENC(XXYYZZ)

配置类中读取时手动解密:

@Configuration
public class DataSourceConfig {@Value("${custom.datasource.password}")private String encryptedPassword;@Beanpublic DataSource dataSource() {String decrypted = CustomEncryptor.decrypt(encryptedPassword);// 使用解密后的密码配置连接池}
}

10.5. 🛡️ 总结

项目

推荐做法

密码

不可明文写入配置文件

加密方式

使用 Jasypt、SM4、AES 等对称加密算法

解密方式

启动时传密钥,或代码中解密

敏感配置项

DB 密码、Redis 密码、MQ 密码、Token、API Key

11. 【推荐】发贴、评论、发送等即时消息,需要用户输入内容的场景。必须实现防刷、内容违禁词过滤等风控策略。

发帖、评论、消息发送等允许用户输入内容的场景中,必须实现防刷和敏感词过滤机制

11.1. 📌 背后原因:

  1. 防刷(反作弊)
    • 防止用户或恶意程序在短时间内大量发送内容,造成系统资源浪费、刷屏或攻击。
    • 常见手段:验证码、限频(RateLimiter)、IP 黑名单、用户行为评分等。
  1. 内容违禁词过滤
    • 避免用户发布非法、色情、暴力、政治敏感、辱骂、诈骗等违规内容。
    • 实现方式:关键词匹配(词库)、模型检测(NLP)、人工审核等。

11.1.1. ❌ 不合规实现(没有风控)

用户评论功能直接保存用户输入内容,没有任何风控措施:

@PostMapping("/comment")
public String postComment(@RequestParam String content) {commentService.save(content); // 无任何过滤或限制return "评论成功";
}

11.2. ✅ 推荐实现(带防刷 + 敏感词过滤)

步骤一:限频防刷(基于用户/IP)

// 使用 Google Guava 的 RateLimiter 限流
private final RateLimiter rateLimiter = RateLimiter.create(1.0); // 每秒1次@PostMapping("/comment")
public ResponseEntity<String> postComment(@RequestParam String content, HttpServletRequest request) {
String ip = request.getRemoteAddr();
if (!rateLimiter.tryAcquire()) {return ResponseEntity.status(429).body("操作过于频繁,请稍后重试");
}// 敏感词过滤
if (SensitiveFilter.containsSensitiveWord(content)) {return ResponseEntity.badRequest().body("内容含有违规词汇");
}commentService.save(content);
return ResponseEntity.ok("评论成功");
}

步骤二:敏感词过滤实现(简单关键词示例)

public class SensitiveFilter {private static final Set<String> sensitiveWords = Set.of("诈骗", "暴力", "政治", "涉黄");public static boolean containsSensitiveWord(String text) {for (String word : sensitiveWords) {if (text.contains(word)) return true;}return false;}
}

11.3. 🛡️ 高级防护建议:

功能

建议做法

防刷

使用令牌桶限流、图形验证码、滑动验证

内容审核

敏感词库 + 自然语言模型过滤(如接入阿里云内容安全、腾讯内容审核)

黑产识别

结合用户行为日志(异常频率、IP、设备号)进行识别

审核策略

提交内容先进入“待审核”状态,通过后再展示

博文参考

http://www.xdnf.cn/news/9947.html

相关文章:

  • 数字人系统源码搭建步骤
  • NHANES指标推荐:UAR
  • LINUX中TOMCAT安装和Nginx源码安装
  • 【深度学习】12. VIT与GPT 模型与语言生成:从 GPT-1 到 GPT4
  • docker-compose部署SpringBoot项目的两种方式(构建镜像和挂载文件)
  • Python打卡第39天
  • Futaba乐迪小飞象Frsky7通多协议接收机KA6说明书
  • hf-mirror断点续传下载权重
  • AAOS系列之(六) ---CarPowerManager中写入的状态,如何在ViewRootImpl中读取问题
  • [git]忽略.gitignore文件
  • 软件项目需求说明书简要模板
  • 【Redis】大key问题详解
  • 【计网】分片
  • websocket在vue中的使用步骤,以及实现聊天
  • MaaS(模型即服务)是什么?
  • IT Tools 部署
  • 食材走T台?Coze+即梦应用实例:实现一键生成食材走秀视频!!(附提示词)
  • [C]基础18.自定义类型:联合和枚举
  • Python实例题:Python实现Zip文件的暴力破解
  • Spring Boot整活指南:从Helo World到“真香”定律
  • 29、请求处理-常用参数注解使用
  • UE路径追踪Path Tracing和Lumen的区别
  • Lambda表达式Stream流
  • 三套知识系统的实践比较:Notion、Confluence 与 Gitee Wiki
  • 关于 smali:2. 从 Java 到 Smali 的映射
  • 无需自建高防:APP遭遇DDoS的解决方案
  • CODEFORCES----1999A - A+B Again?
  • SQL进阶之旅 Day 7:视图与存储过程入门
  • vue的h函数(在 Vue 2中也称为 createElement)理解
  • SAP BASIS常用事务代码ST06 操作系统监控