security-checklist
npx skills add https://github.com/leavesfly/jimi --skill security-checklist
Agent 安装分布
Skill 文档
å®å ¨æ£æ¥æ¸ åæè½å
åºäº OWASP Top 10ï¼å ¨é¢ä¿éåºç¨å®å ¨ã
OWASP Top 10 (2021)
A01:2021 â è®¿é®æ§å¶å¤±æ
é£é©ï¼æªç»ææçç¨æ·å¯ä»¥è®¿é®ææåè½ææ°æ®
鲿¤æªæ½ï¼
- â é»è®¤æç»è®¿é®ï¼æç¡®ææ
- â å®ç°åºäºè§è²çè®¿é®æ§å¶ï¼RBACï¼
- â ç¦ç¨ç®å½å表
- â è®°å½è®¿é®æ§å¶å¤±è´¥å¹¶åè¦
- â éå¶ API 访é®éç
代ç 示ä¾ï¼
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/users")
public List<User> getUsers() {
return userService.findAll();
}
A02:2021 â å 坿ºå¶å¤±æ
é£é©ï¼æææ°æ®æªå å¯æä½¿ç¨å¼±å å¯
鲿¤æªæ½ï¼
- â ä½¿ç¨ HTTPS ä¼ è¾æææææ°æ®
- â éææ°æ®å å¯ï¼æ°æ®åºãæä»¶ï¼
- â ç¦ç¨å¼±å å¯ç®æ³ï¼MD5ãSHA1ï¼
- â 使ç¨å¼ºå¯ç åå¸ï¼bcryptãArgon2ï¼
- â å¯é¥ç®¡çï¼å®æè½®æ¢ãå®å ¨åå¨ï¼
代ç 示ä¾ï¼
// ä½¿ç¨ BCrypt å å¯å¯ç
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String hashedPassword = encoder.encode(rawPassword);
A03:2021 â æ³¨å ¥
é£é©ï¼SQL æ³¨å ¥ãå½ä»¤æ³¨å ¥ãLDAP æ³¨å ¥ç
鲿¤æªæ½ï¼
SQL æ³¨å ¥é²æ¤
// â ä¸å®å
¨
String query = "SELECT * FROM users WHERE username = '" + username + "'";
// â å®å
¨ï¼ä½¿ç¨åæ°åæ¥è¯¢
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, username);
NoSQL æ³¨å ¥é²æ¤
// â 使ç¨åæ°ç»å®
Query query = new Query(Criteria.where("username").is(username));
å½ä»¤æ³¨å ¥é²æ¤
// â ä¸å®å
¨
Runtime.getRuntime().exec("ls " + userInput);
// â å®å
¨ï¼éªè¯å转ä¹
if (userInput.matches("[a-zA-Z0-9]+")) {
ProcessBuilder pb = new ProcessBuilder("ls", userInput);
pb.start();
}
A04:2021 â ä¸å®å ¨è®¾è®¡
é£é©ï¼æ¶æå设计å±é¢çå®å ¨ç¼ºé·
鲿¤æªæ½ï¼
- â å¨è建模
- â å®å ¨è®¾è®¡æ¨¡å¼
- â æå°æéåå
- â 纵深é²å¾¡
- â å®å ¨å¼åçå½å¨æï¼SDLCï¼
A05:2021 â å®å ¨é ç½®é误
é£é©ï¼é»è®¤é ç½®ãæªæ´æ°è½¯ä»¶ãä¸å¿ è¦çåè½
鲿¤æªæ½ï¼
- â æå°åå®è£ ï¼ç§»é¤ä¸å¿ è¦çåè½ï¼
- â ç¦ç¨é»è®¤è´¦æ·åå¯ç
- â é误信æ¯ä¸æ´é²ææä¿¡æ¯
- â å®ææ´æ°åæè¡¥ä¸
- â å®å ¨é 置审æ¥
æ£æ¥æ¸ åï¼
# application.yml
server:
error:
include-stacktrace: never # ç产ç¯å¢ä¸æ´é²å æ
spring:
devtools:
restart:
enabled: false # ç产ç¯å¢ç¦ç¨ devtools
A06:2021 â æåæ»å»åè¿æ¶çç»ä»¶
é£é©ï¼ä½¿ç¨æå·²ç¥æ¼æ´çåºåæ¡æ¶
鲿¤æªæ½ï¼
- â ç§»é¤æªä½¿ç¨çä¾èµ
- â æç»çæ§ä¾èµæ¼æ´
- â ä»å®æ¹æºè·åç»ä»¶
- â 使ç¨ç¾åéªè¯ç»ä»¶å®æ´æ§
å·¥å ·ï¼
# Maven ä¾èµæ£æ¥
mvn dependency:tree
mvn versions:display-dependency-updates
# OWASP Dependency Check
mvn org.owasp:dependency-check-maven:check
A07:2021 â 身份è¯å«å身份éªè¯å¤±è´¥
é£é©ï¼å¼±å¯ç ãä¼è¯ç®¡çä¸å½ãåæ®æ´é²
鲿¤æªæ½ï¼
å¯ç çç¥
- â æå°é¿åº¦ 8 ä½
- â å¤æåº¦è¦æ±ï¼å¤§å°åãæ°åãç¹æ®å符ï¼
- â æ£æ¥å¼±å¯ç å常ç¨å¯ç
- â éå¶ç»å½å¤±è´¥æ¬¡æ°
- â å¤å ç´ è®¤è¯ï¼MFAï¼
ä¼è¯ç®¡ç
// Session é
ç½®
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.maximumSessions(1)
.maxSessionsPreventsLogin(true);
return http.build();
}
A08:2021 â è½¯ä»¶åæ°æ®å®æ´æ§å¤±è´¥
é£é©ï¼ä¸å®å ¨ç CI/CDãèªå¨æ´æ°ãååºåå
鲿¤æªæ½ï¼
- â 代ç ç¾å
- â CI/CD å®å ¨å åº
- â ä¾èµå®æ´æ§éªè¯
- â é¿å ä¸å®å ¨çååºåå
// â ä¸å®å
¨çååºåå
ObjectInputStream ois = new ObjectInputStream(inputStream);
Object obj = ois.readObject();
// â ä½¿ç¨ JSON çå®å
¨æ ¼å¼
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(json, User.class);
A09:2021 â å®å ¨æ¥å¿åçæ§å¤±è´¥
é£é©ï¼æ»å»æ æ³è¢«æ£æµåååº
鲿¤æªæ½ï¼
- â è®°å½ææç»å½ãè®¿é®æ§å¶å¤±è´¥
- â é«ä»·å¼äº¤æå®¡è®¡æ¥å¿
- â æ¥å¿æ ¼å¼è§èå
- â éä¸å¼æ¥å¿ç®¡ç
- â 宿¶åè¦
æ¥å¿ç¤ºä¾ï¼
log.warn("Failed login attempt: user={}, ip={}",
username, request.getRemoteAddr());
log.info("Password changed: user={}, timestamp={}",
username, System.currentTimeMillis());
A10:2021 â æå¡å¨ç«¯è¯·æ±ä¼ªé ï¼SSRFï¼
é£é©ï¼æ»å»è æ§å¶æå¡å¨åèµ·ç请æ±
鲿¤æªæ½ï¼
- â ç¦æ¢ç¨æ·æ§å¶ URL
- â URL ç½åå
- â ç¦ç¨ HTTP éå®å
- â ç½ç»å±é离
// â URL éªè¯
private boolean isAllowedUrl(String url) {
try {
URL u = new URL(url);
String host = u.getHost();
return ALLOWED_HOSTS.contains(host);
} catch (MalformedURLException e) {
return false;
}
}
é¢å¤å®å ¨æªæ½
XSS 鲿¤
// è¾åºè½¬ä¹
String safe = HtmlUtils.htmlEscape(userInput);
// Content Security Policy
response.setHeader("Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline'");
CSRF 鲿¤
// Spring Security èªå¨å¯ç¨ CSRF
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
ç¹å»å«æé²æ¤
// X-Frame-Options
response.setHeader("X-Frame-Options", "DENY");
å®å ¨ååºå¤´
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'
ææä¿¡æ¯æ£æµ
ä¸åºç¡¬ç¼ç çä¿¡æ¯ï¼
- â æ°æ®åºå¯ç
- â API å¯é¥
- â å å¯å¯é¥
- â ç§é¥è¯ä¹¦
- â OAuth å¯é¥
æ£ç¡®åæ³ï¼
# application.yml
spring:
datasource:
password: ${DB_PASSWORD} # ä»ç¯å¢åé读å
å®å ¨å¼åæµç¨
1. 鿱鶿®µ
- è¯å«å®å ¨éæ±
- å¨è建模
2. è®¾è®¡é¶æ®µ
- å®å ¨æ¶æè®¾è®¡
- å®å ¨è®¾è®¡è¯å®¡
3. ç¼ç é¶æ®µ
- å®å ¨ç¼ç è§è
- 代ç 审æ¥
4. æµè¯é¶æ®µ
- å®å ¨æµè¯
- æ¸éæµè¯
- æ¼æ´æ«æ
5. é¨ç½²é¶æ®µ
- å®å ¨é ç½®æ£æ¥
- æå°æéé¨ç½²
6. è¿ç»´é¶æ®µ
- å®å ¨çæ§
- è¡¥ä¸ç®¡ç
- åºæ¥ååº
å·¥å ·æ¨è
éæåæ
- SpotBugsï¼Java 代ç ç¼ºé·æ£æµ
- SonarQubeï¼ä»£ç è´¨éåå®å ¨
- Checkmarxï¼åä¸éæåæå·¥å ·
ä¾èµæ£æ¥
- OWASP Dependency-Checkï¼ä¾èµæ¼æ´æ«æ
- Snykï¼å¼æºä¾èµæ¼æ´æ£æµ
卿æµè¯
- OWASP ZAPï¼Web åºç¨å®å ¨æµè¯
- Burp Suiteï¼æ¸éæµè¯å·¥å ·
å¯é¥æ«æ
- git-secretsï¼é²æ¢å¯é¥æäº¤
- TruffleHogï¼Git åå²å¯é¥æ«æ
å®å ¨æ£æ¥æ¸ å
认è¯ä¸ææ
- å®ç°å¼ºå¯ç çç¥
- 使ç¨å¤å ç´ è®¤è¯
- ä¼è¯è¶ æ¶è®¾ç½®
- å®å ¨çå¯ç éç½®æµç¨
- åºäºè§è²çè®¿é®æ§å¶
æ°æ®ä¿æ¤
- HTTPS å å¯ä¼ è¾
- æææ°æ®å å¯åå¨
- å®å ¨çå¯é¥ç®¡ç
- æ°æ®è±æ
è¾å ¥éªè¯
- ææè¾å ¥éªè¯
- åæ°åæ¥è¯¢é² SQL æ³¨å ¥
- è¾åºç¼ç é² XSS
- æä»¶ä¸ä¼ éªè¯
å®å ¨é ç½®
- ç¦ç¨ä¸å¿ è¦çåè½
- å®å ¨çé»è®¤é ç½®
- éè¯¯æ¶æ¯ä¸æ´é²ææä¿¡æ¯
- å®ææ´æ°ä¾èµ
æ¥å¿çæ§
- è®°å½å®å ¨äºä»¶
- å®¡è®¡å ³é®æä½
- å¼å¸¸åè¦
- æ¥å¿ä¿æ¤
åºæ¥ååº
åç°æ¼æ´å
- è¯ä¼°å½±åï¼èå´ã严éç¨åº¦
- é离系ç»ï¼é²æ¢è¿ä¸æ¥æå®³
- ä¿®å¤æ¼æ´ï¼ç´§æ¥è¡¥ä¸
- éªè¯ä¿®å¤ï¼å®å ¨æµè¯
- æ»ç»å¤çï¼é²æ¢å次åç