工程師校招筆試:從漏洞修復(fù)到安全編碼全解析)
2018年秋季我投了美麗聯(lián)合的信息安全開發(fā)工程師崗位筆試完走出考場的時候我最大的感受是這不是一份傳統(tǒng)意義上的滲透測試卷子更像一份“帶著安全意識的開發(fā)真題”。當(dāng)時我對安全崗位的想象還停留在“挖洞、打CTF、寫exp”但真正坐到考場里打開試卷之后才發(fā)現(xiàn)這份試卷考的東西跟我想象的完全不一樣它不要求你掌握多冷門的利用鏈也不考花式的滲透技巧反而把大量分值放在HTTP協(xié)議、編碼習(xí)慣、漏洞的修復(fù)方案甚至還有一道“修復(fù)我給你的有漏洞代碼”的編程題。后來我順利進入了安全開發(fā)的方向回頭看這份試卷其實它非常清晰地畫出了這個崗位的能力畫像首先是工程師然后才是安全工程師。這篇文章就結(jié)合這份試卷的考點分布、典型題目和我的備考、失分經(jīng)歷聊聊安全開發(fā)工程師校招筆試到底在考什么。1. 從試卷結(jié)構(gòu)看安全開發(fā)崗位的定位1.1 安全開發(fā)崗和滲透測試崗的試卷差異我先說一個很多人容易誤解的點安全開發(fā)工程師筆試和滲透測試工程師筆試是完全兩套出題邏輯。滲透測試崗更喜歡考信息收集、漏洞利用、內(nèi)網(wǎng)橫向、權(quán)限維持題型里大量出現(xiàn)“這個漏洞怎么打”“給出利用方式”。而安全開發(fā)崗的試卷更像“軟件工程師試卷安全基礎(chǔ)知識”它默認(rèn)你首先能寫代碼其次再談安全。美麗聯(lián)合這份試卷整體給我留下的印象是客觀題大概占50%簡答/分析題占30%編程題占20%但即使是客觀題也多數(shù)在問“下列哪種寫法能防御XX攻擊”而不是“下列哪個工具有XX功能”。這個出題邏輯背后是崗位的日常工作。安全開發(fā)工程師通常要做SDL、安全中間件、風(fēng)控系統(tǒng)、代碼審計平臺、加解密服務(wù)也可能要寫業(yè)務(wù)安全接口比如登錄保護、短信防刷、內(nèi)容安全過濾。你不是一個只在項目上線前做一次滲透的“外掛”而是要和業(yè)務(wù)研發(fā)并行把安全能力嵌入到每一行代碼里。所以筆試必須首先篩選出代碼功底扎實的人然后再看你有沒有安全直覺。我當(dāng)時最大的教訓(xùn)是用了大量時間刷CTF Web題但對HTTPS握手過程、對稱加密和非對稱加密的適用場景這類基礎(chǔ)題卻模棱兩可。結(jié)果試卷前面一大塊基礎(chǔ)題做得并不順暢。后來才明白安全開發(fā)筆試考察的是“穩(wěn)定輸出”而不是“某個瞬間的靈感”。1.2 為什么試卷里有一半題目在考開發(fā)基礎(chǔ)考完復(fù)盤時我數(shù)了一下這份試卷里純安全知識題大概只占一半剩下的是編程語言基礎(chǔ)、數(shù)據(jù)結(jié)構(gòu)、操作系統(tǒng)、網(wǎng)絡(luò)協(xié)議這些常規(guī)開發(fā)崗題。很多人不理解安全開發(fā)為什么要考鏈表反轉(zhuǎn)為什么要考進程和線程區(qū)別我在筆試時也嘀咕過。工作一段時間之后才想明白安全開發(fā)工程師日常要做代碼審計你必須足夠熟悉常見語言的特性和坑才能發(fā)現(xiàn)別人代碼里的安全隱患而做安全應(yīng)急響應(yīng)時你要能快速定位到進程、端口、日志文件離不開操作系統(tǒng)和網(wǎng)絡(luò)基礎(chǔ)。從招聘方角度也很好理解。美麗聯(lián)合這類電商公司安全團隊要支撐的業(yè)務(wù)鏈路很長從用戶注冊、登錄、下單、支付到營銷活動每一個環(huán)節(jié)都有安全風(fēng)險。如果只招一個只會打流行的洞而不會寫生產(chǎn)代碼的人進來之后既讀不懂業(yè)務(wù)代碼又沒法跟研發(fā)有效協(xié)作會非常痛苦。所以試卷寧可把標(biāo)準(zhǔn)定在“合格的開發(fā)有安全意識”也不希望招一個“精通利用但完全沒有工程能力”的人。除此之外安全開發(fā)崗的同學(xué)還要經(jīng)常跟運維打交道處理線上告警、加固服務(wù)器、排查入侵痕跡。這些工作對Linux命令、網(wǎng)絡(luò)協(xié)議、數(shù)據(jù)庫操作的熟練度要求非常高。試卷里考Linux端口查看和日志查找其實就是在提前篩查你有沒有真實接觸過服務(wù)器而不是只會在本地虛擬機里跑跑工具。2. 基礎(chǔ)題安全開發(fā)工程師必須“秒答”的知識點2.1 HTTP與Web基礎(chǔ)幾乎每年必考這份試卷開頭就是一批Web基礎(chǔ)選擇題覆蓋了HTTP請求方法、狀態(tài)碼含義、Cookie和Session區(qū)別、同源策略、常見的請求頭Referer、Origin、X-Forwarded-For等。這些內(nèi)容看起來簡單但卻是安全開發(fā)的基石。比如同源策略它決定了跨域請求能不能攜帶Cookie很多CSRF和CORS配置問題能不能利用都跟同源策略的邊界理解有關(guān)。再比如X-Forwarded-For后端如果直接用這個頭來獲取客戶端IP做風(fēng)控那攻擊者完全可以自己偽造請求頭繞過這類問題在我后面做風(fēng)控系統(tǒng)時幾乎每周都能遇到。我建議準(zhǔn)備這類題目不要死記硬背而是把每個知識點串成一條線一次完整的HTTP請求從客戶端發(fā)出到服務(wù)端處理完畢經(jīng)過了哪些節(jié)點哪些東西可以被用戶控制哪些頭是代理服務(wù)器加的哪些頭可以用代碼偽造。這種理解方式不僅應(yīng)對選擇題后面做漏洞分析題也很有幫助。我整理了一個自己復(fù)習(xí)時反復(fù)看的表格分享出來給大家參考考點常見考查方式需要掌握的深度HTTP方法GET/POST/PUT/DELETE冪等性知道方法語義能判斷哪些請求可能被濫用狀態(tài)碼301/302/401/403/502等能快速定位問題知道哪些狀態(tài)碼會繞過安全邏輯Cookie屬性HttpOnly、Secure、SameSite能說明每個屬性在什么攻擊下起作用同源策略協(xié)議、域名、端口三者都相同能解釋CORS和跨域請求的邊界請求頭偽造X-Forwarded-For、Referer、Origin知道哪些頭可被客戶端控制不能直接信任到這里要特別強調(diào)一個筆試高頻坑Referer和Origin在CSRF防護里經(jīng)常被提到但Referer有時會因為隱私策略被瀏覽器去掉所以嚴(yán)謹(jǐn)?shù)姆桨竿ǔ烧呓Y(jié)合或者直接使用CSRF Token。如果你能在答案里提到這一層閱卷人會認(rèn)為你真正遇到過線上問題。2.2 密碼學(xué)常識不是讓你實現(xiàn)算法而是知道怎么用密碼學(xué)在安全開發(fā)筆試中占比很穩(wěn)定。那次考試?yán)镂矣∠蠛苌畹囊坏李}是對比對稱加密、非對稱加密和哈希算法的區(qū)別并給出一個實際使用場景。這道題表面在考概念實際上刷掉了很多只知道AES、RSA名詞但不知道選型的人。安全開發(fā)工程師不是密碼學(xué)專家但要能判斷什么場景該用AES-GCM而不是ECB什么時候該用RSA加密而不是直接用SHA-256保存用戶密碼以及JWT用HS256和RS256分別意味著什么。這里展開說一下實際工作中最常用的幾個判斷用戶密碼存儲絕不能存明文或簡單的MD5應(yīng)該用加鹽的慢哈希算法比如bcrypt、scrypt或argon2。加鹽的目的在于避免相同密碼產(chǎn)生相同哈希值防止彩虹表直接命中。數(shù)據(jù)完整性校驗用HMAC而不是普通哈希。HMAC帶有一個密鑰能防止攻擊者在不知道密鑰的情況下篡改數(shù)據(jù)和重算校驗值。接口傳輸加密實際項目通常不會單純用RSA加密整段數(shù)據(jù)因為非對稱加密慢且有長度限制。常見做法是用RSA或ECDH交換對稱密鑰隨后用AES-GCM這類對稱加密算法傳輸數(shù)據(jù)這就是混合加密體系。筆試如果考到“如何設(shè)計一個安全的登錄接口”一般都會涉及密碼哈希和會話管理。我建議在答案里不要只寫“用bcrypt”還要提到破解防護比如限制登錄失敗次數(shù)、加入驗證碼、對異常IP做風(fēng)控。這些點組合起來才能體現(xiàn)你是從工程角度思考而不是單純背了一個算法名。2.3 Linux與網(wǎng)絡(luò)基礎(chǔ)別在送分題上丟分第三塊基礎(chǔ)題是Linux命令和網(wǎng)絡(luò)常識。常見的有查看端口監(jiān)聽用什么命令、如何查找占用8080端口的進程、iptables規(guī)則如何寫、如何查看系統(tǒng)日志網(wǎng)絡(luò)方面則會考TCP三次握手、常見的端口號22、80、443、3306、6379等、DNS解析過程。這類題對做過實際部署的人非常簡單但對只刷題庫的人來說容易記混。安全開發(fā)工程師寫一個加固腳本、排查一個入侵痕跡、定位一個服務(wù)異常都會用到這些命令。比如日志審計你要去/var/log下找nginx的access.log、mysql的慢查詢?nèi)罩具€要通過journalctl查看systemd服務(wù)的輸出這些操作如果只靠背命令但不知道日志文件放哪里實際工作中也會卡殼。所以筆試出現(xiàn)這種題本質(zhì)上是在確認(rèn)你有沒有真實接觸過服務(wù)器。我個人的建議是備考時一定要親自動手搭一個Linux虛擬機把Nginx、MySQL、Redis裝一遍然后模擬部署一個Web應(yīng)用。期間練習(xí)幾個核心命令netstat -tlnp看端口、ps aux看進程、ss -tlnp替代netstat、lsof -i:8080查端口占用、tail -f看實時日志、grep過濾關(guān)鍵詞。這些命令不復(fù)雜但能確保你在筆試中寫答案時不會卡殼也能給面試官留下“可落地”的印象。3. 應(yīng)用安全題考察的不是POC而是漏洞修復(fù)能力3.1 SQL注入的修復(fù)思路從拼接參數(shù)到預(yù)編譯應(yīng)用安全題是這份試卷的重頭戲。其中SQL注入是必考項。但它的考法不是讓你提交一個payload而是給你一段JDBC或MyBatis的代碼問你是否存在注入風(fēng)險如果存在怎么改。我當(dāng)時看到這種題還挺意外因為平時練的都是“構(gòu)造注入語句拿到數(shù)據(jù)庫內(nèi)容”很少去想在業(yè)務(wù)代碼里怎么修。正確的修復(fù)思路無外乎三種預(yù)編譯PreparedStatement、參數(shù)化查詢、對動態(tài)拼接做嚴(yán)格白名單校驗。筆試?yán)镒罘€(wěn)妥的答案是首選預(yù)編譯。比如在Java中使用?占位符綁定參數(shù)而不是用字符串拼接SQL。下面我用一段簡化的偽代碼說明// 有問題直接拼接用戶輸入 String sql SELECT * FROM users WHERE username username ; // 修復(fù)后使用PreparedStatement String sql SELECT * FROM users WHERE username?; PreparedStatement pstmt conn.prepareStatement(sql); pstmt.setString(1, username); ResultSet rs pstmt.executeQuery();在MyBatis里則要警惕${}的使用因為${}是直接拼進SQL的很容易產(chǎn)生注入通常情況下應(yīng)該用#{}。如果確實需要動態(tài)表名、排序字段那也一定要做白名單映射而不是直接引用前端傳來的字段名。比如排序字段只允許asc或desc表名只能從枚舉中取值。很多人在筆試時還會糾結(jié)“是不是還要對輸入做特殊字符過濾”。我的建議是預(yù)編譯已經(jīng)能解決絕大多數(shù)SQL注入問題再加一層過濾屬于縱深防御但如果只是簡單替換單引號反而可能破壞業(yè)務(wù)數(shù)據(jù)的正確性。所以答案里可以把過濾作為輔助措施但核心必須落在參數(shù)化查詢上。3.2 XSS與CSRF一個講輸出轉(zhuǎn)義一個講請求校驗XSS和CSRF往往放在一起考但很多人在筆試時會把兩者搞混。XSS的核心是攻擊者往頁面里注入了腳本所以防御重點在輸出編碼和輸入過濾CSRF的核心是瀏覽器自動攜帶身份憑證讓服務(wù)端以為請求來自用戶本人所以防御重點在請求來源校驗、CSRF Token、SameSite Cookie。我建議大家寫答案時先寫清楚區(qū)別再各自展開這樣閱卷人會覺得你是真的理解而不是背模板。實際筆試中XSS可能會給你一段前端模板讓你找問題。比如用innerHTML拼接用戶輸入或者給某個URL參數(shù)直接賦值到href屬性。修復(fù)時要注意上下文在HTML標(biāo)簽內(nèi)、屬性內(nèi)、JavaScript字符串內(nèi)、CSS內(nèi)編碼方式各不相同。這里有一個容易被忽略的點富文本場景下你不能直接轉(zhuǎn)義所有HTML而應(yīng)該用白名單過濾標(biāo)簽和屬性比如允許b、a但去掉onclick、javascript:等危險內(nèi)容。CSRF的修復(fù)則經(jīng)常要你分析一個請求的防護方案比如轉(zhuǎn)賬接口。修復(fù)思路包括驗證Referer是否來自本站、校驗請求中是否攜帶隨機Token、給關(guān)鍵Cookie加SameSite屬性。如果再進階一點可以提一下在Java Spring Security中CSRF過濾器是怎么工作的。它的核心機制是在渲染表單時注入一個隱藏的_csrf字段表單提交時后端會比較Session中的值。對AJAX請求則需要在請求頭中攜帶Token。筆試時如果你能把這些細(xì)節(jié)寫出來會比只寫“加Token”專業(yè)很多。3.3 越權(quán)與SSRF開發(fā)者最容易忽略的邊界除了Web三大經(jīng)典這份試卷還考了越權(quán)和SSRF。越權(quán)題通常會給你一個訂單詳情接口/api/order?id123然后問你能怎么攻擊怎么修。水平越權(quán)的修復(fù)核心是服務(wù)端重新判斷資源歸屬不能只信任請求參數(shù)里的訂單ID而要從登錄態(tài)中獲取當(dāng)前用戶ID再校驗該訂單是否屬于當(dāng)前用戶。垂直越權(quán)的修復(fù)則依賴權(quán)限控制框架和接口級別的鑒權(quán)注解比如Spring Security中的PreAuthorize。越權(quán)漏洞經(jīng)常被開發(fā)同學(xué)忽略是因為很多人在編碼時默認(rèn)“前端看不到刪除按鈕用戶就不會操作”但攻擊者完全可以直接構(gòu)造請求。所以筆試時你要特別強調(diào)前端控制只是體驗優(yōu)化真正的權(quán)限判斷必須在后端完成。SSRF的考點主要是URL可以被攻擊者控制時服務(wù)端會去請求任意內(nèi)網(wǎng)地址導(dǎo)致內(nèi)網(wǎng)探測和攻擊。修復(fù)思路包括過濾IP拒絕私網(wǎng)地址和環(huán)回地址、限制請求的協(xié)議和端口、使用統(tǒng)一的HTTP客戶端的SSRF防護組件。很多公司會在代碼里實現(xiàn)一個安全請求庫底層做掉這些限制。筆試如果讓你寫修復(fù)方案能把“校驗?zāi)繕?biāo)地址是否合法、禁止重定向后再次請求內(nèi)網(wǎng)地址、用白名單域名”這幾點寫上就能拿大部分分。這里還要提醒一個進階點DNS解析也可能被用作繞過比如一個域名解析到內(nèi)網(wǎng)IP而不是直接在URL里寫127.0.0.1。因此完善的SSRF防護通常需要二次解析校驗甚至在建立連接后再次驗證對端IP。能在筆試中寫出這一點說明你確實踩過坑。4. 編碼題筆試?yán)镒畛R姷摹敖o漏洞代碼修bug”模式4.1 一段有問題的登錄代碼長什么樣編程題是安全開發(fā)筆試?yán)镒钪苯永_差距的部分。美麗聯(lián)合這份試卷我記得有一道登錄接口的代碼分析代碼片段大致是一個POST接口接收username和password然后從MySQL查詢用戶信息并校驗密碼整體邏輯看起來沒有任何報錯但至少有三個安全隱患SQL注入、明文密碼校驗、登錄錯誤提示信息泄露了用戶是否存在。這種題非常貼近實際因為登錄接口是所有業(yè)務(wù)系統(tǒng)最核心的入口也是最容易成為攻擊目標(biāo)的地方。下面我用Python Flask寫一個簡化版本方便大家理解我當(dāng)時看到的代碼結(jié)構(gòu)app.route(/api/login, methods[POST]) def login(): username request.json.get(username) password request.json.get(password) sql SELECT * FROM users WHERE username%s AND password%s % (username, password) user db.execute(sql).fetchone() if user: return login success else: return username or password error這段代碼在筆試中出現(xiàn)頻率極高。它的問題一眼就能看出來SQL語句直接拼接了用戶輸入密碼以明文存儲并直接比對返回信息區(qū)分了“用戶不存在”和“密碼錯誤”相當(dāng)于把系統(tǒng)的用戶枚舉漏洞直接暴露給攻擊者。筆試要求你修復(fù)本質(zhì)上就是在考察你有沒有真實寫過安全的后端接口。4.2 修復(fù)思路與評分點修復(fù)版本應(yīng)該至少做到使用參數(shù)化查詢避免SQL注入、對密碼做哈希后與數(shù)據(jù)庫中的密文比對、統(tǒng)一登錄錯誤提示、增加登錄頻率限制。如果題目還要求返回一個會話標(biāo)識那還要考慮Session的固定攻擊防護和Cookie安全屬性。閱卷時通常是按點給分每個安全點都能拿到對應(yīng)分?jǐn)?shù)寫清楚比堆代碼更有效。我給大家一個相對完整的修復(fù)代碼示例app.route(/api/login, methods[POST]) def login(): username request.json.get(username) password request.json.get(password) user db.execute( SELECT id, username, password_hash FROM users WHERE username?, (username,) ).fetchone() if user and check_password_hash(user.password_hash, password): session[user_id] user.id session.permanent True return login success # 統(tǒng)一錯誤信息避免用戶枚舉 return invalid username or password需要注意幾個細(xì)節(jié)第一查詢只根據(jù)username定位用戶密碼校驗放在應(yīng)用層第二使用check_password_hash底層是加鹽哈希第三錯誤信息統(tǒng)一定為“invalid username or password”不存在用戶名和密碼錯誤分開提示。再加上登錄次數(shù)限制這個接口的安全強度就高很多了。在回答這類題時我建議把“發(fā)現(xiàn)問題、分析原因、給出修復(fù)代碼、補充測試場景”四步走結(jié)構(gòu)寫清楚。你不需要把整個接口寫得完美無缺但一定要讓閱卷人看到你有系統(tǒng)性的安全思考。比如修復(fù)SQL注入時不僅改這一行還要在數(shù)據(jù)訪問層統(tǒng)一使用預(yù)編譯修復(fù)密碼明文時不僅加個哈希函數(shù)還要提到加鹽和選擇合適的哈希算法。4.3 安全編碼習(xí)慣如何在筆試中體現(xiàn)這道題反映出的其實是一個優(yōu)秀安全開發(fā)工程師的日??吹饺魏我欢未a時先下意識找數(shù)據(jù)流入口和信任邊界對用戶輸入完全不信任對輸出和存儲都按不安全場景處理。這種習(xí)慣在筆試中會體現(xiàn)在你的答案注釋里。比如修復(fù)代碼時你可以用注釋寫清楚“這里原本可被SQL注入已改為參數(shù)化查詢”這既是給自己梳理思路也是讓閱卷人看到你的判斷過程。編程語言上安全開發(fā)筆試大部分時候不會限制語言但Java和Python是出現(xiàn)頻率最高的。建議備考時把這兩種語言最常見的Web開發(fā)框架的寫安全問題都過一遍比如Java的Spring Boot、Python的Flask/Django。知道它們默認(rèn)的防注入機制是什么、默認(rèn)的Session存儲方式是什么、默認(rèn)的CSRF保護是否開啟這些細(xì)節(jié)往往就是筆試?yán)锢_差距的關(guān)鍵。我后來在帶校招生時也會做類似的測試發(fā)現(xiàn)能寫出“先分析風(fēng)險點再給出修復(fù)代碼”的同學(xué)往往在實際工作中也更擅長代碼審計和上下線安全評審。因為這背后體現(xiàn)的是結(jié)構(gòu)性思維而不只是會背某個漏洞的利用方式。所以在筆試復(fù)習(xí)階段建議養(yǎng)成一個習(xí)慣每看到一個漏洞都問自己一句“如果我在代碼里遇到了我會怎么改”。5. 拉開差距的附加題安全方案設(shè)計與邏輯漏洞挖掘5.1 給一個電商訂單系統(tǒng)設(shè)計安全方案這份試卷的最后一題是一道綜合設(shè)計題大概意思是有一個類似美麗聯(lián)合的電商平臺用戶下單支付全流程請設(shè)計一套安全方案。這種開放式問題沒有標(biāo)準(zhǔn)答案但恰恰是最能體現(xiàn)工程能力的一道題。只答“加個驗證碼、做數(shù)據(jù)加密”肯定不夠要分層去設(shè)計。我當(dāng)時是按照“客戶端→網(wǎng)關(guān)/接入層→應(yīng)用層→數(shù)據(jù)庫層”的鏈路來寫后來工作后復(fù)盤這個思路是對的。接入層要做HTTPS強制、WAF策略、IP風(fēng)控、頻率限制應(yīng)用層要做參數(shù)校驗、權(quán)限校驗、業(yè)務(wù)防重、支付回調(diào)簽名數(shù)據(jù)層要做敏感字段加密、數(shù)據(jù)庫審計、備份恢復(fù)。同時還要考慮安全運維比如日志要留夠、異常要有告警、密鑰要統(tǒng)一管理。如果能畫一條完整的鏈路再在每個節(jié)點標(biāo)出具體的安全措施這道題基本就穩(wěn)了。為了更直觀我列了一個簡化版的安全設(shè)計表層次面臨的主要威脅對應(yīng)安全措施接入層惡意掃描、CC攻擊、爬蟲WAF、IP頻率限制、行為驗證碼應(yīng)用層越權(quán)、邏輯漏洞、注入?yún)?shù)校驗、鑒權(quán)、防重冪等業(yè)務(wù)層優(yōu)惠券套利、短信轟炸風(fēng)控規(guī)則、配額限制、異步審核數(shù)據(jù)層數(shù)據(jù)泄露、弱口令敏感字段加密、最小權(quán)限、審計日志這里的關(guān)鍵不是把所有方案堆上去而是每寫一個安全措施都要說清楚它對應(yīng)什么威脅。比如“支付回調(diào)接口必須驗證簽名并且校驗訂單金額和回調(diào)金額是否一致”這就比“做好支付安全”具體得多。閱卷人看到這種答案會覺得你真的理解電商系統(tǒng)的風(fēng)險在哪里。5.2 邏輯漏洞案例分析優(yōu)惠券、越權(quán)、驗證碼除了安全方案很多公司還會出一兩道邏輯漏洞題。電商業(yè)務(wù)最容易出問題的鏈路就是營銷和支付優(yōu)惠券是否可以重復(fù)領(lǐng)取是否可以疊加使用下單數(shù)量是否可以超賣支付回調(diào)是否可以重復(fù)通知訂單狀態(tài)是否可以跳步更新。這些邏輯漏洞沒有統(tǒng)一的規(guī)則但筆試考核的是“如果我要攻擊這個系統(tǒng)我會從哪個環(huán)節(jié)下手”的思維。舉個例子一個優(yōu)惠券接口用戶點擊領(lǐng)取后只判斷“是否已領(lǐng)取”但同一個用戶可以通過并發(fā)請求繞過前端置灰狀態(tài)產(chǎn)生大量同時到達的領(lǐng)取請求。修復(fù)方案往往不是單純加鎖而是用數(shù)據(jù)庫唯一約束或者Redis的SETNX做冪等。再比如重置密碼短信驗證碼如果不綁定會話且不限次數(shù)攻擊者可以直接遍歷。這類題的答案重點在于能不能想到并發(fā)和冪等。我在筆試時遇到過一道具體的邏輯漏洞題支付成功后返回success但系統(tǒng)在更新訂單狀態(tài)之前先發(fā)送了通知消息。如果消息隊列重復(fù)投遞訂單狀態(tài)被更新兩次就可能出現(xiàn)“一單多扣”或“多發(fā)一次貨”。修復(fù)方案是在消費端做冪等用訂單號加一個去重表重復(fù)消息直接丟棄。這個場景在校招筆試?yán)锍霈F(xiàn)其實是在考察你有沒有分布式系統(tǒng)的基礎(chǔ)認(rèn)知。5.3 如何組織答案才能拿到高分綜合設(shè)計題的回答一定要有結(jié)構(gòu)。我建議用“威脅模型對應(yīng)控制措施”的方式先列可能存在的威脅再針對威脅寫控制方案。威脅可以從外部攻擊者、內(nèi)部惡意用戶、數(shù)據(jù)泄露、業(yè)務(wù)異常等角度列舉控制措施要落到具體技術(shù)比如“為了防止短信轟炸用Redis記錄手機號維度每分鐘發(fā)送次數(shù)上限5次”。這種回答方式比泛泛而談“我們要做好安全”要專業(yè)得多。另外開放式問題要敢于寫自己熟悉的東西不要什么都寫但寫不深。閱卷人通常能看出你到底有沒有實操經(jīng)驗。如果真的做過某個安全組件哪怕是很小的功能也可以多展開比如“我在學(xué)校項目里實現(xiàn)過登錄防爆破模塊用的是滑動窗口計數(shù)器”這比背十種安全產(chǎn)品效果更好。還要注意時間分配。綜合設(shè)計題放在最后分值不一定是最高但一定不能空著。哪怕時間只剩15分鐘也要先寫一個分層的框架把最容易得分的安全措施填進去比如HTTPS、參數(shù)校驗、越權(quán)校驗、日志審計這四個點可以快速寫完然后有余力再擴展。千萬不要小看這些“常識性”答案它至少證明你有完整的工程視野。6. 基于這套試卷的備考路線與避坑指南6.1 三個月備考路線基礎(chǔ)、刷題、實踐把這份試卷研究明白后我的備考路線大致分成了三個階段。第一個月補基礎(chǔ)重點看HTTP協(xié)議、計算機網(wǎng)絡(luò)、操作系統(tǒng)、數(shù)據(jù)庫原理和常用開發(fā)框架目標(biāo)是能把一個請求從瀏覽器到數(shù)據(jù)庫的完整流程講清楚而且在每個環(huán)節(jié)都能指出哪里可能被攻擊。第二個月刷安全專項包括OWASP Top 10、常見漏洞的原理和防御、密碼學(xué)基礎(chǔ)以及大量筆試題不只是背答案而是自己要能寫修復(fù)代碼。第三個月做綜合練習(xí)找一些開源項目做代碼審計嘗試提交漏洞報告同時每天花一小時做算法題保持手感。關(guān)于參考書和資料我當(dāng)年用到的有《Web安全深度剖析》《白帽子講Web安全》、OWASP官方文檔和各類安全公眾號的筆試題解析。這里要特別提醒現(xiàn)在網(wǎng)上能搜到的“安全開發(fā)工程師筆試”資源其實不多更有效的方式是直接拿一些開源電商項目做代碼審計比如找一個小型Java或Python項目用IDE搜索SQL拼接、文件上傳、反序列化等風(fēng)險點然后嘗試修復(fù)。這個過程既能鍛煉代碼閱讀能力又能積累真實案例面試時還能當(dāng)項目經(jīng)歷講。6.2 筆試現(xiàn)場的答題策略這里分享一些我自己的考場經(jīng)驗。首先發(fā)下試卷后先瀏覽一遍全卷把會做的題目先做掉不會的標(biāo)記出來不要在選擇題上糾結(jié)太久。其次編程題不要一上來就寫代碼先把思路寫在草稿紙上包括要修哪幾個點每修一個點對應(yīng)的漏洞是什么。最后開放題一定要寫滿哪怕思路不成熟有結(jié)構(gòu)、有層次的回答也比空白好得多因為安全方案設(shè)計題考的就是思路不是標(biāo)準(zhǔn)答案。另外做題時要有“按點得分”的意識。比如讓你解釋CSRF的防御方案至少寫出Token校驗、同源校驗、SameSite Cookie三個點每個點都能得分。如果只寫一個“用Token”即使方向?qū)α艘部赡芤驗楦采w不全丟分。寧可多列幾個措施也不要只寫一個“標(biāo)準(zhǔn)答案”因為安全本來就不是單點防御。還要注意字體和時間管理。有些同學(xué)在編程題上寫了一大堆思路但代碼淹沒在文字里閱卷人很難快速找到關(guān)鍵點。我建議代碼單獨放在一個塊里前面用一句話說清楚改了什么比如“修復(fù)點參數(shù)化查詢防止SQL注入”這樣閱卷效率會高很多。6.3 我自己當(dāng)年失分的地方希望你別再踩我在那次筆試中失分最多的不是最后的方案設(shè)計反而是最前面的密碼學(xué)選擇題和程序員容易忽略的Cookie屬性。原因是我當(dāng)時把大量時間花在CTF的題目上覺得“這才是安全”忽略了對基礎(chǔ)概念的準(zhǔn)確掌握。后來做面試復(fù)盤時我才意識到安全開發(fā)崗位的筆試從來不是為了篩選“最會PWN的人”而是為了篩選“最能讓業(yè)務(wù)代碼安全落地的人”。如果你現(xiàn)在也在準(zhǔn)備類似的校招筆試希望你能把一半的精力放在工程基礎(chǔ)上多寫代碼、多看開源框架的源碼對任何漏洞的認(rèn)識都落到修復(fù)本身。這個思路在后來的工作中也一直幫到我也希望對你有所幫助。最后再分享一個小技巧筆試結(jié)束后不管感覺好壞都把題目回憶一遍尤其是那些你不確定的知識點回來立刻查資料補上。這套試卷本身就是一份免費的復(fù)習(xí)提綱把它吃透比刷十套同類題都有用。我當(dāng)時就是把錯題整理成一個文檔后來面試時還遇到好幾個類似的問題直接就把答案順出來了。如果你也在準(zhǔn)備信息安全開發(fā)方向的校招不妨用這個思路來對待每一次筆試會有意想不到的收獲。