奇安信秋招开发岗笔试复盘:安全编码与基础考点全解析 📅 发布时间:2026/9/1 17:10:46 👁 浏览次数: 这套卷子我反复看了好几遍2020年奇安信秋招软件开发方向试卷3整体风格和互联网大厂的开发笔试很不一样。普通互联网公司考的是算法题刷得勤不勤奇安信这套卷子明显在暗示一件事我们招的是写安全产品的开发不是只会写CRUD的码农。卷子里藏着不少安全编码意识、内存布局、输入校验这类考点如果你只是刷LeetCode冲过去选择题可能会先栽一轮。我认识几个当年一起秋招的朋友考完交流了一下大家的共识是这套试卷的编程题难度不算顶格中等偏上但选择题和填空题覆盖面很广C、操作系统、网络、数据结构、安全基础全都有。所以这篇文章我就把整套卷子的考察方向、核心考点、编程题思路以及安全公司开发岗笔试特有的“隐藏分”一次讲清楚给后面准备安全方向开发岗的同学做参考。1. 试卷整体结构与考察方向拆解1.1 题型分布和分值节奏先说整体结构。按照2020年那场秋招的常见安排软件开发方向试卷一般是90分钟到120分钟题型大概分为四块单选、多选、填空、编程。分值上编程题通常占大头单题20到30分选择和填空单题分值不高但数量多加起来也能决定你能不能进下一轮。我当时估算的分布大致是题型题量单题分值考察重点单选题20道左右2分数据结构、C/Java基础、操作系统、网络多选题5道左右3分概念辨析、边界条件、安全编码填空题5道左右2分输出结果、算法复杂度、简单计算编程题2道20-30分链表/动态规划/字符串处理这套分布不算激进但有一个很明显的倾向基础题占了一半以上的分数。也就是说哪怕编程题只AC了一道只要选择和填空正确率高整体成绩不会太难看。反过来如果觉得编程题难直接把前面基础题做扎实也能和其他人拉开差距。多选题是典型的丢分重灾区。普通互联网公司笔试多选少而且多选通常就考一两道概念题。奇安信这套卷子里的多选偏爱考“哪些说法正确”“哪些操作可能导致内存泄漏”“哪些HTTP方法不安全”这类组合判断少选多选都不得分。这就逼着你必须把概念掌握到“能判断对错”的颗粒度而不是“大概知道”。1.2 从考点倒推岗位画像把整套卷子的考点串起来看基本能还原出这个岗位要什么样的人。首先编程底层要扎实C/Java内存模型得清楚因为安全产品很多要跟底层系统打交道缓冲区溢出、野指针这类问题在普通业务代码里是bug在安全产品代码里就是漏洞。其次网络基础和操作系统不能虚网络安全产品大量涉及报文分析、进程监控、权限控制不理解TCP状态转换、进程调度、用户态内核态切换很多业务场景根本推不动。最后具备基本的安全编码意识写代码时知道用户输入是不可信的、路径要做规范化、格式化字符串不能直接拼用户数据这些都是安全公司开发区别于普通开发的核心能力。所以这套卷子本质上在筛选“底子好、有安全敏感度”的工程师而不是单纯筛算法竞赛选手。想投安全方向开发岗的同学备考思路就必须跟着这个画像走。2. 基础考点复盘容易被刷下去的选择题和填空题2.1 数据结构概念题比手写题更阴数据结构这块编程题可能会考链表和动态规划但选择题考得更细全是概念辨析。我印象比较深的有这么几类。第一类是二叉树的性质。给定一棵完全二叉树有n个节点问叶子节点有几个、深度是多少、第i个节点的父节点下标是多少。这类题要求你对完全二叉树数组存储的结论很熟父节点下标是i/2、左孩子是2i、右孩子是2i1以及叶子节点数为n/2向上取整。如果这些结论长期不碰临时推导虽然也能推出来但会浪费时间。第二类是排序算法的稳定性和复杂度。选择题会直接问“下列哪些排序算法是稳定的”答案里会混着快排、堆排、归并、插入排序。稳定排序有冒泡、插入、归并、基数不稳定排序有选择、快排、堆排。这个结论本身不难背但题目不会只考稳定它还会叠加“最好/最坏时间复杂度”来出多选比如“下列说法正确的是快排最坏O(n^2)、堆排空间O(1)、归并稳定且平均O(n log n)”。这种组合判断最容易在多选里翻车。第三类是哈希与B树。哈希冲突处理方式要能说出开放定址法和链地址法的区别装载因子对性能的影响。B树则爱考“为什么数据库索引用B树而不是B树”——非叶子节点不存数据可以放更多索引项、叶子节点用链表串起来方便范围查询这两个理由是高频答案但单选题很少直接考原话它会给四个选项让你判断哪句描述错了比如把“叶子节点存储所有数据”说成“非叶子节点也存储全部数据”来误导你。我的建议是数据结构备考不要只刷算法题把课本里那些“结论性内容”过一遍尤其是复杂度、稳定性、存储结构特征。安全公司笔试对这些基础概念的考查密度远高于普通互联网公司。2.2 网络与操作系统面试前必背的几类结论网络题在卷子里占的比例不小而且安全公司考网络有一个特点偏爱考“状态”和“协议交互细节”不是简单问TCP和UDP有什么区别。比如TCP三次握手和四次挥手时各个状态怎么迁移SYN_SENT、ESTABLISHED、FIN_WAIT_1、TIME_WAIT这些状态在什么条件下出现。2020年那套卷子里就有一道选择题问“主动关闭方在发送最后一次ACK后进入什么状态”答案是TIME_WAIT但选项里混了CLOSE_WAIT和LAST_ACK如果不清楚四次挥手的过程很容易选成CLOSE_WAIT。HTTP相关考点也很安全公司特色比如HTTP状态码语义、GET和POST的区别以及“哪些HTTP方法是幂等的”。普通开发笔试可能只问GET和POST参数位置安全公司会追问幂等性因为这在设计RESTful API和防护策略时都是基础概念。操作系统部分主要考进程和线程、调度算法、死锁条件。进程间通信方式管道、消息队列、共享内存、信号量是高频考点尤其要清楚共享内存为什么效率最高但需要同步机制配合。死锁的四个必要条件互斥、请求保持、不可剥夺、循环等待也常考有时候会换一种问法“破坏循环等待条件可以预防死锁对应哪种策略”答案是资源有序分配。这些概念都不难但知识点杂建议考前集中背一遍尤其是那些“4个条件”“3种状态”“5种通信方式”之类的结构化结论选择题里非常吃香。2.3 编程语言与内存布局C/Java考点对照卷子里编程语言相关的题目明显偏向C和底层内存这是安全公司开发岗的特点。如果是Java方向岗位也会考JVM内存区域和垃圾回收但整体占比不如C高。C考点里虚函数和虚表是绝对的重点。题目会问含有虚函数的类实例化后内存布局中第一个成员是什么答案是虚表指针或者问虚析构函数的作用选项里会出现“防止内存泄漏”和“正确释放派生类资源”后者才是本质原因。RAII、智能指针unique_ptr、shared_ptr也是高频点多选会问“哪些做法可以有效避免内存泄漏”选项包括使用智能指针、new和delete成对出现、容器存放裸指针后手动遍历释放等。内存分区题也很常见局部变量在栈上、new出来的对象在堆上、全局变量和静态变量在全局区、常量字符串在只读常量区。安全公司考这个不只是考概念它背后是缓冲区溢出和栈布局的底层逻辑所以这类题分值不高但在安全方向的面试里属于“你以为考的是C其实考的是漏洞利用基础”的思路。Java方向如果出现常考的是final关键字、String与StringBuilder区别、HashMap底层结构、并发包里的ConcurrentHashMap分段锁/CAS机制。虽然Java方向不会深挖缓冲区溢出但并发编程的考点同样能筛掉一批人。3. 编程题核心高频题型的思路与模板3.1 链表反转递归与迭代两条路都要会链表题在安全公司笔试里出现频率非常高2020年奇安信这套卷子编程题里就有一道链表相关的题。链表题之所以受欢迎是因为它既能考指针操作基本功又能在O(1)空间限制下考逻辑能力而且边界条件多很容易区分水平。最经典的就是单链表反转。我建议至少掌握两种写法不仅为了这道题本身更因为很多复杂链表题都是它的变体。迭代法思路清晰用三个指针prev、cur、next遍历每次把cur指向prev然后整体后移。代码模板struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; ListNode* reverseList(ListNode* head) { ListNode* prev nullptr; ListNode* cur head; while (cur ! nullptr) { ListNode* next cur-next; cur-next prev; prev cur; cur next; } return prev; }递归法代码更短但理解门槛略高。核心思路是先反转head-next之后的链表得到新头结点然后把head接到链表尾部最后把head-next置空。ListNode* reverseListRecursive(ListNode* head) { if (head nullptr || head-next nullptr) { return head; } ListNode* newHead reverseListRecursive(head-next); head-next-next head; head-next nullptr; return newHead; }笔试时如果时间紧张我更推荐迭代法不容易递归过深出错而且边界条件只需要处理空链表和单节点两种情况。如果题目进阶成“每K个一组反转链表”也是用迭代法加一个哨兵头节点最方便这个变体很值得提前练一下因为它经常被拿来当第二道编程题的铺垫。3.2 最长递增子序列从DP到二分优化的演进动态规划是编程题的常客2020年那套卷子编程题里出现了一道典型的DP题。如果让我押安全公司开发笔试的DP题型最长递增子序列LIS出现的概率极高因为它既能用朴素O(n^2)动态规划解又能用贪心二分优化到O(n log n)可以很好地区分应试者水平。朴素DP思路定义dp[i]表示以nums[i]结尾的最长递增子序列长度初始值全是1。遍历每个i再回头找所有j i如果nums[j] nums[i]就更新dp[i] max(dp[i], dp[j] 1)。最终答案是dp数组的最大值。int lengthOfLIS(vectorint nums) { int n nums.size(); if (n 0) return 0; vectorint dp(n, 1); int res 1; for (int i 1; i n; i) { for (int j 0; j i; j) { if (nums[j] nums[i]) { dp[i] max(dp[i], dp[j] 1); } } res max(res, dp[i]); } return res; }如果n的范围达到10^5量级O(n^2)就会超时这时候要用贪心二分。维护一个tails数组tails[len]表示长度为len的递增子序列中末尾元素的最小值。遍历nums时在tails里二分找到第一个大于等于当前元素的位置并替换如果当前元素比所有末尾值都大则扩展tails长度。这个做法能过的数据范围远大于朴素DP笔试中有时间建议直接写优化版能体现算法功底。这类题的通用套路是识破“最长/最小/方案数”问题里的DP结构先写出状态定义和转移方程再考虑能不能优化。安全公司笔试的编程题通常不会上特别偏的模型把LIS、编辑距离、背包问题这老三样练熟基本覆盖90%的DP考法。3.3 字符串处理实战以“压缩字符串”为例除了链表和DP字符串处理也是安全公司笔试的固定方向之一而且往往和安全编码有点关联比如反转字符串、判断回文、实现字符串匹配、去除重复字符。这类题难度不大但极其考验边界条件处理一个i和i写反就得调试半天。2020年试卷的编程题里有一道和字符串压缩类似的题。题目原型是给定一个字符数组把连续重复字符压缩成“字符次数”的形式要求原地修改并返回新长度。比如chars [a,a,b,b,c,c,c]压缩后是[a,2,b,2,c,3]返回6。这道题有两个关键点一是双指针法一个指针遍历原始字符一个指针写入结果位置二是当连续字符个数大于等于10时需要转成字符串逐位写入不能只写一个字符。后者是很多人丢分的地方因为字符数组里只能逐字符存数字10以上的场景很容易漏处理。int compress(vectorchar chars) { int n chars.size(); int write 0; int i 0; while (i n) { int j i; while (j n chars[j] chars[i]) { j; } chars[write] chars[i]; int count j - i; if (count 1) { string cntStr to_string(count); for (char c : cntStr) { chars[write] c; } } i j; } return write; }这类题在笔试中最大的坑不是算法想不到而是测试用例覆盖不全。“所有字符都不重复”“所有字符都相同”“次数超过9”这三个边界用例提交之前一定要在脑子里过一遍。很多同学刷题时习惯了在线OJ自动判断笔试时没有反馈就必须靠自己的测试用例意识去补位。4. 安全方向的隐藏分为什么安全公司会考这些4.1 路径遍历与输入校验一道题看穿安全编码思维安全公司的开发笔试和普通互联网公司最大的区别就是它会考安全编码题。这类题通常不会单独出一道“请解释什么是SQL注入”而是把安全思维揉进选择题、填空题甚至编程题里。热词搜索里“奇安信输入验证路径遍历”这个方向正好是这类考点的代表。路径遍历Path Traversal的核心是用户传入的文件名或路径没有被正确处理攻击者可以通过../../这类序列跳出预期目录读取敏感文件。比如程序要打开/var/data/目录下的文件用户传入../../etc/passwd如果代码直接把用户输入拼到路径后面就会读到不该读的文件。安全编码的做法是先规范化路径再校验最终路径是否仍在允许的目录范围内。用Java写的话核心是调用Paths.get(baseDir, userInput).normalize().toString()然后判断结果是否以baseDir开头。用Python写就是os.path.realpath后再startswith判断。但这里有个细节startswith判断可能被/var/data_evil这种前缀绕过所以校验时要在目录后面加上分隔符再比。笔试中这类知识点的考法往往是选择题“以下哪种写法可以有效防御路径遍历攻击”选项里会有“过滤用户输入中的..”“使用白名单校验文件名”“先规范化路径再校验前缀”“直接把拼接好的路径交给系统调用”。正确答案是规范化校验单纯过滤..是典型的黑名单绕过点攻击者可以用URL编码、双重编码等方式绕过。这个考点背后的本质是安全公司开发的每行代码都要默认“用户输入是不可信的”。普通开发写代码时假设用户是好人安全产品开发写代码时假设用户是攻击者代码里对输入的处理方式完全不同。平时刷算法题可能不太关注这个思维但考安全公司之前一定要把你的代码视角切换过去。4.2 栈溢出、格式化字符串与内存安全基础除了输入校验内存安全相关的概念也是安全公司笔试题里的常客。选择题可能会给一段C代码问执行后是否会发生缓冲区溢出缓冲区大小、拷贝长度哪个参数决定了风险。这类题背后考的是栈布局的基本概念局部变量在栈上相邻排列数组越界写入会覆盖相邻变量如果覆盖到返回地址程序流程就可能被劫持。格式化字符串漏洞也是一类经典考点。选择题会给出printf(user_input)这样的代码问有什么风险。答案是格式化字符串漏洞攻击者可以用%s读取栈上任意地址的内存或者用%n往任意地址写数据。正确写法是printf(%s, user_input)永远不要把用户输入当成格式化字符串的第一个参数传进去。整数溢出在安全编码里也经常出现。比如malloc(strlen(input) 1)如果strlen(input)返回一个很大的值加1之后可能溢出变成很小的正整数导致分配一块很小的缓冲区然后memcpy拷贝大量数据进去形成堆溢出。这类知识点在普通开发岗笔试里基本不会出现但奇安信这类安全公司会考因为它直接关系到底层产品代码的安全性。我不是说每个投安全公司开发岗的人都得成为漏洞挖掘专家但至少要知道这些基础漏洞的原理和防御手段。现在很多安全公司的笔试面试都会聊到OWASP Top 10路径遍历、命令注入、SQL注入这些基础分类最好能用自己的话讲清楚。一个写业务代码的开发可以不懂攻击方法一个写安全产品的开发如果也不懂那写出来的产品自己都防不住自己。5. 备考策略与实战心得5.1 笔试现场的时间分配策略基于这套卷子的结构和分值分布我建议的答题顺序是先花35到40分钟把选择、多选、填空全部做完再留50到60分钟做编程题最后10分钟检查。为什么先把客观题做完因为客观题分值是确定的做对就有分编程题可能一道题卡住半小时也AC不了如果先把时间耗在编程题上前面的分数反而丢了。做多选题要格外谨慎。多选少选多选都不得分遇到不确定的选项宁可不选也不要冒险。安全编码相关的多选通常只有一个“最正确”的组合平时练习时就要养成“逐项判断对错”的习惯而不是凭感觉圈选项。编程题先读清楚题意再动手。很多同学看到题目很像LeetCode原题兴奋地直接写之前背的答案结果输入输出格式对不上或者没注意到题目加了“必须原地修改”的限制。建议花两分钟把输入范围、返回类型、边界条件都画在草稿纸上再开始写代码。5.2 安全公司开发岗的刷题侧重点如果目标是安全方向的开发岗位刷题不能只盯着LeetCode Hot 100。我的建议是分成三条线并行走。第一条线是经典算法题重点刷链表、二叉树、字符串、动态规划、双指针。这些是笔试编程题的主要来源。LeetCode的Hot 100和剑指Offer覆盖得比较全刷两遍以上每道题都能独立写出来编程题基本不会慌。第二条线是计算机网络和操作系统基础题。重点背TCP状态迁移、HTTP状态码、死锁条件、进程调度算法、内存分区、用户态内核态切换。这些不止笔试要用后面的技术面试还会被反复追问。刷题类App里也有专门的计算机基础题库可以利用碎片时间过一遍。第三条线是安全编码题。这一条线容易被忽视但恰恰是奇安信这类公司的差异化考点。重点学习路径遍历、命令注入、SQL注入、XSS、CSRF、缓冲区溢出、格式化字符串漏洞的原理和修复方式。不要求能写Exploit但至少要能识别不安全的代码写法并能写出对应的安全版本。我当时复习安全编码时用的办法是每学一个漏洞类型就自己写一段“有漏洞的代码”和一段“修好的代码”做对比这个对比过程就是笔试多选题的答题逻辑给你四种写法判断哪些安全哪些不安全。5.3 复盘之后的几条实在建议最后聊几条实际操作层面的建议都是我复盘这套卷子之后觉得最有价值的东西。第一一定要提前去牛客网刷几套该公司或同类安全公司的真题。笔试系统和LeetCode的手感差别很大尤其是不支持本地IDE的在线编辑器用起来会觉得自己手残。提前适应牛客网的代码编辑器和输入输出模板可以避免考场上因为不熟悉环境浪费时间。第二C方向的同学把智能指针和STL容器的底层实现过一遍。unique_ptr的移动语义、shared_ptr的引用计数、vector扩容机制是选择题的高频素材。Java方向的同学把HashMap的put流程、ConcurrentHashMap的锁粒度演进、垃圾回收算法过一遍。这些内容的命中率很高值得花时间。第三编程题如果没有思路可以先写暴力解法确保拿一部分分。很多在线判题系统是按测试用例给分的暴力解法能过基础用例就有基础分比空着强。如果暴力解法都写不出来那就把思路和伪代码写在注释里至少让阅卷人看到你的思路方向。第四填空题通常考输出结果比如“请写出以下代码的输出结果”。这类题分值不高但往往有两个坑变量作用域和指针修改。遇到指针相关代码画一张内存示意图把每个变量的地址和值标出来正确率会大幅提升。这一步看上去费时间实际上比心算可靠得多。写在最后我个人的体会是安全公司开发岗的笔试更大的价值不在于那两道编程题而在于它帮你建立了一种“写代码前先想攻击面”的思维方式。考完这套卷子之后我再看自己以前写的代码感受完全不一样了。以前写文件上传接口只想着格式校验现在会想用户传入文件名能不能带路径分隔符目录拼接后会不会绕过前缀判断异常分支里会不会把堆栈信息泄露出去。这种视角的转变比多刷一百道算法题更重要。如果你正在准备奇安信或者其他安全厂商的开发岗不妨找几套真题先感受一下别急着刷难题。把基础数据结构、操作系统、网络、安全编码这几条线拉平比任何单项突出都管用。笔试只是第一关但第一关的筛选逻辑已经告诉你这个岗位需要什么样的人基础扎实、代码素养高、脑子里始终装着安全和边界。