
百度2015安全研发笔试卷说实话这套卷子在当年互联网安全圈里流传度不低。2015年那会儿移动互联网正处在爆发期各家大厂的安全团队都在疯狂扩张百度自然也不例外。如果你正准备安全研发方向的面试或者想看看大厂笔试到底怎么考察一个安全工程师这套卷子很值得拿来当标本拆一拆。它不是那种纯考漏洞利用细节的渗透测试卷而是更偏向“你能不能把安全能力用代码落地成产品”的研发型考卷。这篇文章我会按试卷的典型考点模块来复盘结合我自己做安全研发这些年的经验和踩过的坑把每一类题背后真正想考察的东西讲清楚。不管你是刚开始接触安全研发的在校生还是已经工作几年想跳槽的工程师这篇文章应该都能给你一些有参考价值的思路。1. 2015年百度安全研发笔试卷整体拆解考的不是漏洞利用是安全工程思维1.1 安全研发和渗透测试岗的笔试考法完全不一样很多人准备安全笔试时有个误区——疯狂刷漏洞利用技巧、记各种payload结果到了安全研发的考场上发现题目风格完全不是自己想象的那样。我当年面过不少安全岗位最大的感受是安全研发岗和渗透测试岗虽然都叫“安全工程师”但笔试的侧重点差异非常大。渗透测试岗更看重攻击思维给你一个目标你能不能在短时间内发现漏洞、利用漏洞、形成完整的攻击链。而安全研发岗的核心诉求是“你能不能让防御能力落地”。2015年百度安全实验室和基础安全团队正处于高速建设期很多安全能力都要从零到一自研比如WAF规则引擎、风控系统、App加固方案、日志审计平台这些都需要安全研发工程师自己写代码实现。所以那套笔试卷的题目设计很典型漏洞原理要懂但更重要的是你得给出修复方案和防御代码安全工具要会用但考场上更常见的是让你现场写一段安全编码的代码系统架构要理解因为安全产品本质上是高并发、高可用的业务系统。1.2 试卷考点分布五大模块一条主线我根据对2015年前后百度安全研发笔试套路的了解把考点整理成了下面这张表。虽然每年具体题目会有变化但考察框架大体上是稳定的。考点模块典型题目方向考察核心能力Web安全SQL注入原理与防御、XSS/CSRF、SSRF、文件上传绕过漏洞理解与安全编码移动安全Android四大组件安全、DEX加固、SO库逆向、JNI调用客户端攻防与加固二进制安全栈溢出、堆溢出、格式化字符串、ROP基础底层原理与防护机制密码学哈希存储、对称/非对称加密选型、随机数安全密码学工程应用工程能力编程题、风控系统设计、日志处理、安全工具编写研发落地与架构能力主线就一条从“发现问题”到“解决问题”的完整闭环。漏洞原理只是起点能不能给出可落地、可维护、性能可接受的解决方案才是安全研发工程师真正的价值所在。这个思路在2015年是这样放到十年后的今天依然没有变。2. Web安全代码审计考点从漏洞原理到修复方案的完整链路2.1 SQL注入不只是要你写出攻击语句更要写对修复代码Web安全模块里SQL注入几乎是必考项。2015年那会儿很多业务代码还是字符串拼接SQL的方式注入漏洞一抓一大把。试卷上常见的出题方式是给你一段有明显问题的Java或PHP代码让你指出漏洞点并给出修复方案。从研发视角来看正确答案的核心只有一条使用参数化查询PreparedStatement / PDO预处理。以Java为例正确写法是这样的// 错误写法直接拼接SQL存在SQL注入风险 String sql SELECT * FROM users WHERE name username AND password password ; Statement stmt connection.createStatement(); ResultSet rs stmt.executeQuery(sql); // 正确写法使用PreparedStatement参数化查询 String sql SELECT * FROM users WHERE name ? AND password ?; PreparedStatement pstmt connection.prepareStatement(sql); pstmt.setString(1, username); pstmt.setString(2, password); ResultSet rs pstmt.executeQuery();我当时在笔试里还额外补充了一点为什么预编译能防住注入因为经过预编译后SQL语句的结构在数据库端已经确定用户输入只被当作参数值处理而不是拼接成SQL语法的一部分。这个原理说清楚了比死记硬背“用PreparedStatement”答案更有说服力。另外还有个容易丢分的地方参数化查询并不能覆盖所有场景。比如动态表名、动态排序字段这些无法用占位符的参数就需要做白名单校验。试卷里如果给了这种“预编译也解决不了”的场景你还能想到白名单方案那基本上就稳了。2.2 XSS与CSRF防护不是一个点而是一整套编码规范XSS跨站脚本攻击和CSRF跨站请求伪造在2015年的笔试卷里出现的频率也非常高。XSS的考察重点是存储型XSS的防御因为影响面最大。研发岗的正确答案要覆盖输入校验和输出编码两个维度。输入校验方面不能只靠前端校验服务端必须再做一层。这里有个关键细节过滤和转义要区分开。过滤是删除危险字符转义是把危险字符转换成安全形式。以输出场景为例在HTML上下文中输出用户内容必须做HTML实体编码把、、、、这些字符转成lt;、gt;等。# Python Django模板中的自动转义2015年前后主流的防护方式之一 {{ user_content|escape }} # 或者使用更严格的第三方库 from html import escape safe_content escape(user_input, quoteTrue)CSRF的考察点则更偏向方案设计。2015年的时候CSRF Token校验是主流方案比如在表单里生成一次性Token服务端收到请求时校验。我当年在试卷里补充了为什么Token要绑定Session、为什么需要设置合理的过期时间这些细节比只写一个“加Token”要出彩得多。提示回答XSS和CSRF题目时千万别只写一种修复手段。把“输入过滤、输出编码、HttpOnly Cookie、CSP、SameSite、Token校验”这些手段按场景组合起来回答才能体现出安全研发和普通开发的差异。2.3 SSRF、文件上传与命令注入看似偏门实则高频这三个考点在2015年前后的安全笔试里不算最热门但百度这类体量的公司反而会出因为他们内部业务复杂、组件多这类漏洞发生的概率很高。SSRF服务端请求伪造考察的是你知不知道如何限制服务端发起的请求。修复思路一般是对URL做协议白名单只允许HTTP/HTTPS、对目标IP做内网地址封禁包括IPv4保留地址、IPv6链路本地地址等、对DNS解析结果做二次校验。当年很多人的答案只写了“过滤内网IP”但没写DNS Rebinding的绕过风险这就容易被扣分。命令注入的修复方案相对固定尽量不用系统命令执行函数实在要用则对参数做严格的转义和过滤或者用白名单校验参数格式。文件上传考点则集中在“如何安全地保存上传文件”文件名随机化、后缀白名单、MIME类型和服务端文件头双重校验、存储目录与Web根目录分离、上传目录禁止脚本执行权限。这几点说全了基本就能拿全这一类题的分数。3. 移动安全方向试题解析Android加固与客户端防护3.1 DEX加固原理为什么加固后的App还要在内存中修复DEX2015年是Android安全最热闹的年份之一加固、脱壳、逆向的攻防战打得火热。笔试卷里移动安全的比重不小最常见的出题方向是“简述Android App加固的基本原理”。我当时是这么答的加固的核心思路是把真正可执行的DEX文件进行加密打包进APK时只是一个壳DEX壳DEX在运行时先执行解密出原始DEX后动态加载进内存同时要修复ClassLoader的加载路径。因为Android的类加载机制依赖DexFile直接加载解密后的DEX字节数组需要反射调用openMemoryDexFile或者把解密后的DEX写入私有目录再动态加载。另外还有一个容易被忽略的细节加固后的App在运行时要让内存中的DEX在脱壳后恢复正常功能这涉及ClassLoader结构中的pathList和dexElements的重构。这道题考的不只是你会不会用加固工具而是在考察你理不理解安卓的类加载机制。3.2 SO库安全与JNI调用链土办法反而最实用除了DEX加固2015年试卷里还经常出现SO层安全的题目比如“如何保护Native层的关键算法”“如何防止SO库被静态分析”。这类题的答题思路要从两个方向展开第一个方向是反调试。在JNI_OnLoad里周期检查/proc/self/status中的TracerPid字段非零说明被调试器附加了直接退出进程。第二个方向是字符串和函数名混淆。IDA Pro静态分析最依赖的线索就是导出函数名和字符串交叉引用你可以在编译时用-fvisibilityhidden隐藏符号把关键字符串拆开存储、运行时拼接。注意很多人在试卷上长篇大论写ollvm混淆、VMP加固但实际研发中在成本和性能之间做取舍更重要。2015年很多商业方案太贵自研团队往往用“导出函数隐藏字符串加密关键流程反调试”这几招组合性价比最高。这个思路放到今天依然适用因为攻击成本和收益的决定性因素没变攻击者需要的时间和人力成本越高被攻击的概率就越低。3.3 客户端风控SDK设备指纹采集题背后的工程陷阱移动安全方向还有一类题很特别——风控SDK设计。2015年百度的风控体系已经覆盖了搜索、贴吧、网盘等多个业务线这类题目出现得顺理成章。试卷上的典型问法是“如果要设计一个Android端的数据采集SDK用来支持风控系统识别设备唯一性你会采集哪些数据如何保证数据不被篡改”我当年的思路是分三层回答。第一层是设备标识采集包括IMEI、MAC地址、Android ID、设备型号、系统版本、屏幕分辨率、传感器列表等第二层是数据完整性保护对采集到的字段用MD5或HMAC-SHA256生成签名摘要防止数据在传输过程中被篡改第三层是抗伪造因为IMEI和MAC在Android 6.0之后拿不到了需要结合多种标识生成稳定的设备指纹。这道题其实还隐含了一个工程陷阱采集SDK不能影响宿主App的性能和稳定性。如果在主线程做I/O采集或者频繁上报会被业务方骂惨。正确做法是异步采集、本地缓存、批量上报这个点答出来能让阅卷人觉得你具备真实研发经验。4. 二进制安全与密码学考点复盘底层功底的试金石4.1 栈溢出与ROP基础理解缓解机制比记住利用步骤更重要二进制安全模块在研发岗笔试卷中不会出得像CTF那么深但基础概念一定会考。栈溢出是最经典的考点程序把用户输入复制到固定大小的栈缓冲区时没有校验长度导致返回地址被覆盖程序跳转到攻击者指定的地址执行恶意代码。笔试里经常顺带考防护机制因为研发岗写代码时要知道这些缓解机制是怎么工作的。NXNo-Execute让栈和堆上的代码不可执行ASLR随机化栈地址、堆地址和共享库基址让攻击者没法预测地址Canary在栈上放一个随机值函数返回前检查是否被篡改。ROPReturn-Oriented Programming的考点一般就是概念级别在NX开启的情况下攻击者复用程序里已有的指令片段gadget拼凑成恶意执行链。研发岗的回答重点是“怎么缓解”除了NX和ASLR还可以用RELRO只读重定位表、PIE位置无关可执行文件提高利用门槛。我在实际写安全代码时的体会是编译器开启的防护选项-fstack-protector-all、-z noexecstack、-pie -fPIE对防御栈溢出攻击极其有效。笔试时把这个经验写进去得分会很不一样因为这是真实项目里会做的动作而不是纸上谈兵。4.2 密码学考点Hash存储、加密选型与随机数的坑密码学在安全研发笔试中主要考工程实践不会让你去算离散对数。最常见的考点是“密码的存储方式”明文存储是肯定不行的直接MD5存储也是不行的正确做法是加盐的慢哈希算法比如bcrypt、scrypt、PBKDF2。2015年那会儿很多团队还在用md5(password)这种原始方案所以考卷上有意设计了这道题。我答的时候补充了一个细节盐值salt必须每个用户随机且独立不能是全局固定盐否则攻击者可以用彩虹表批量破解。另一个高频考点是AES加密的模式选择。ECB模式不能选因为同样的明文会产生同样的密文泄露数据分布特征CBC模式是2015年前后用得最多的但要注意IV初始化向量必须随机且每次加密都要变化GCM模式最好它自带认证能力能同时保证机密性和完整性。这个选型思路到今天还是通用的。密码学模块还有一个容易忽略的坑——随机数。如果Random类的种子可以被预测那么生成的密钥和Token都不安全要用SecureRandom。我当年在笔试里甚至遇到过出题人把随机数种子设为固定值让你指出问题这就是典型的踩坑现场。5. 安全研发的工程能力题从安全工具编码到风控系统设计5.1 安全工具开发的编程题从需求到实现安全研发卷子的最后一部分通常有编程题而且出的题都是“安全工具开发”类型。比如“写一个函数从一份HTML文件里提取所有外链URL并去重”或者“写一个日志分析脚本统计Top N的访问IP”。这类题目考量的是编码基本功、边界处理和性能意识。以日志分析为例我当时的做法是先用正则匹配IP再用哈希表做统计最后用堆或直接排序取Top K。但重点难点在于边界日志格式不统一怎么办、正则性能太慢怎么办、内存放不下怎么办。我在答案里补充了“先用流式读取分块处理、再用外部排序取Top K”的方案这比只写一个readlines全读进内存的答案要成熟。一个更贴合安全研发场景的例题是“实现一个简单的敏感信息扫描器扫描文本中是否包含手机号、身份证号、银行卡号”。核心是正则表达式但性能优化点在于尽量用编译后的正则对象、减少回溯、支持分段流式扫描。import re # 编译正则避免每次调用都重新编译 phone_pattern re.compile(r(?!\d)1[3-9]\d{9}(?!\d)) id_card_pattern re.compile(r(?!\d)\d{17}[\dXx](?!\d)) bank_card_pattern re.compile(r(?!\d)\d{16,19}(?!\d)) def scan_sensitive_info(text): result {phones: [], id_cards: [], bank_cards: []} result[phones] phone_pattern.findall(text) result[id_cards] id_card_pattern.findall(text) result[bank_cards] bank_card_pattern.findall(text) return result这道题我特别想强调一点正则里加上前后边界断言能显著降低误报率。比如手机号匹配时(?!\d)和(?!\d)是为了防止匹配到一串超长数字的中间片段。这种细节是真实业务中会遇到的也是面试官区分你有没有实战经验的金标准。5.2 风控系统与DDoS防护的设计题答的是架构思维设计题是安全研发笔试的大轴。2015年的设计题常见方向是“设计一个验证码系统”或“设计一个Web层面的DDoS防护方案”。这类题没有标准答案考察的是你有没有体系化思考能力。以验证码系统为例我的答题框架是四步第一步验证码的生成模块包括图形扭曲算法、干扰线/噪点、存储方式Session/Redis第二步验证码的校验时机是服务端校验还是前端只做展示第三步防爆破策略包括单IP请求频率限制、图形验证码有效期、失败次数锁定第四步验证码被OCR识别或打码平台绕过的兜底方案比如切换行为式验证码。DDoS防护的答题思路更偏网络层。比如答“基于流量特征的DDoS防护”需要先从攻击类型分类入手SYN Flood、UDP Flood、HTTP Flood分别怎么识别、怎么防护。识别靠流量统计基线防护靠清洗设备和CDN分流。研发岗的加分项是把“清洗策略下发的链路”讲清楚检测端发现异常流量下发规则到调度中心调度中心再下发到各个防护节点这个闭环是自动化的不能靠人肉运维。我当年见过一个不错的答案把DDoS防护拆成了“检测-调度-清洗-回源”四层每一层都给出了可行的技术方案。这种结构化的表达方式哪怕技术细节不是100%准确也给阅卷人留下了好印象。6. 答题避坑实录与复盘心得那些我踩过的坑和现在的建议6.1 笔试中最常见的三个致命误区我把这些年见到的笔试答题坑整理了一下排名前三的分别是第一个误区是只答利用不答修复。很多人答SQL注入就开始写 or 11 --写了半天利用语法修复方案一句话带过。但安全研发岗的评分标准恰恰相反修复方案才是重点。你至少要把“参数化查询、最小权限数据库账号、完善日志审计”这三层防御都写上。第二个误区是概念背诵而不理解原理。比如答XSS防御时只写“对输入做过滤”但说不清楚过滤和转义的区别更说不清不同输出上下文HTML、属性、JavaScript、CSS、URL需要不同的编码策略。这种答案在研发岗的笔试里拿不到高分。第三个误区是忽略了业务场景的约束。比如答密码学题时建议所有接口都用国密算法或者答风控SDK设计时要求全链路加密。方案本身没错但在性能、兼容性、用户体验上可能根本不现实。出题人想看到的是你在安全目标和业务成本之间做妥协和权衡的能力。6.2 对准备安全研发方向的同学我再多说几句用现在的眼光回看2015年的这套试卷很多具体技术已经迭代了2015年还在讨论的DEX加固方式现在有了更成熟的VMP方案当年还在手写正则做敏感信息扫描现在已经可以用深度学习模型做NLP级别的识别了。但试卷背后的考察主线一直没变过你是一个能写代码的工程师还是一个懂安全的开发。如果让我给现在的求职者一个建议那就是不要死记漏洞库而是把手底下的每一行代码都代入攻击者的视角看一遍。当你写一个文件上传接口的时候你要想到会不会有人上传WebShell当你设计一个注册登录系统时你要想到用户名能不能注入SQL、密码能不能被撞库。这种“代码还没写攻击场景已经在脑子里跑了一遍”的习惯才是安全研发岗最值钱的能力。最后再聊一个小技巧。笔试答题的时候遇到设计类题目哪怕时间紧张也尽量画出一个结构化的框架再展开。不管是安全产品还是普通业务系统面试官看重的首先是你思考问题有没有体系然后才是具体技术方案。框架对了细节有点瑕疵反而问题不大框架乱了细节再精彩也容易被当作“散装知识”。这一点我在带新人、看简历、做面试评审的时候体会特别深。