奇安信2020开发岗笔试考点拆解:从C/C++到安全基础
先说明一个事情:奇安信2020年的软件开发工程师岗位笔试,和市面上大多数互联网公司的笔试风格不太一样。它不是单纯刷LeetCode就能过的,里面掺杂了大量安全基础、系统底层、网络协议的题目,很多科班出身、算法题刷得很顺的同学,反而挂在基础题上。我当年帮团队筛简历、出过几轮笔试题目,后来也带过不少新人,把这一整套考察逻辑摸得比较透。这篇就按"2020软件开发工程师(二)"这套题目的典型结构,把考点、准备思路和我踩过的坑一次性讲清楚。
1. 先搞清楚奇安信开发岗考什么:从岗位JD反推考点
1.1 奇安信的产品线决定了开发岗的技术栈
奇安信不是做纯互联网业务的,它做的是政企安全、终端安全、云安全、大数据安全分析这类To B/To G业务。这意味着软件开发工程师日常接触的技术栈,和做电商、做社交的团队有本质区别。
- 终端安全产品(比如天擎),核心是Windows/Linux底层开发,驱动、进程管理、文件系统过滤是家常便饭,所以C/C++是绝对主力。
- 安全大数据平台,涉及海量日志采集、存储、分析,Java和Go用得比较多,但底层日志采集组件仍然是C/C++。
- 云安全方向,要跟虚拟化、容器、K8s打交道,Go语言几乎是标配。
- 安全服务与攻防对抗,需要理解漏洞原理、恶意代码行为,开发人员如果不懂攻击,很难写出真正有效的防御代码。
所以,奇安信的软件开发工程师笔试,必然是以C/C++为主、计算机网络和操作系统并重、同时搀杂安全基础知识的综合体。2020年这一套题,基本就是这样设计的。
1.2 招聘流程与笔试节奏
2020年奇安信的校招流程大致是:网申 -> 在线笔试 -> 技术一面 -> 技术二面 -> HR面。笔试一般安排在周末,时长两小时左右,题目分为选择题、简答题和编程题三块。
选择题大约20到30道,覆盖C/C++语法、数据结构、网络协议、操作系统、安全基础。简答题一般有两三道,考查某个具体技术点的理解和设计思路。编程题一到两道,难度在LeetCode中等偏上,但不完全是算法题,有时候会结合安全场景出题。
这里有个很重要的点:笔试的通过率并不完全取决于编程题做没做出来。如果选择题正确率太低,编程题全对也可能被刷。我见过好几个算法很强、但C++指针和网络基础一塌糊涂的候选人,笔试直接被筛掉。反过来,选择题扎实、编程题用暴力解法拿部分分的人,反而能进面试。
1.3 笔试考察的三个层级
我把它总结为三个层级:
第一层是"基础功底",就是C/C++语法、内存模型、STL、数据结构这些硬功夫。这一层决定你能不能过笔试门槛。
第二层是"系统理解",包括操作系统进程线程、内存管理、TCP/IP协议栈、HTTP协议。这一层决定你在面试时能不能跟面试官聊到同一个频道。
第三层是"安全敏感度",包括常见的Web漏洞原理、加密算法、安全编码习惯。这一层是奇安信区别于普通互联网公司的核心考点,也是很多人容易忽略的地方。
后面几个部分,我按这个逻辑逐个拆解。
2. 语言与数据结构:安全公司笔试的"重灾区"
2.1 为什么不是Java为主,而是C/C++
很多同学觉得奇怪,大学里Java学的挺多,怎么笔试全是C/C++?原因很简单:安全产品需要直接跟操作系统打交道,做驱动、做hook、做内存操作,Java做不到,Go在某些底层场景也不够灵活。C/C++依然是安全软件的主干语言。
因此,笔试选择题中关于C/C++的题目占比通常在30%到40%。2020年这套题里面,指针和内存相关的内容出了不少。
2.2 指针、内存、STL的常见考题
我挑几个高频点,每个都是我实际在笔试和面试中见过的。
指针与 const 的组合
这类题看起来很简单,但错误率极高。比如:
const char *p; // p指向的内容不可变 char * const p; // p本身不可变 const char * const p; // 内容和指针都不可变笔试不会直接让你背定义,而是给你一段代码,问哪一行编译报错。这种题考的是对声明从右往左读的理解。我的经验是先看const修饰的是谁,再判断能不能赋值。
内存泄漏与野指针
典型的题目会给出一个函数,函数内部new了一个对象,然后return了另一个指针,问哪里有泄漏。或者给你一个类,析构函数没有写成虚函数,问delete基类指针时会发生什么。
这里不只是背概念,要理解对象生命周期。比如:
class Base { public: ~Base() { std::cout << "Base destructor\n"; } }; class Derived : public Base { public: ~Derived() { std::cout << "Derived destructor\n"; } }; Base *p = new Derived(); delete p;这段代码delete p时只会调用Base的析构函数,Derived的析构函数不会执行。如果Derived里面持有堆内存,就泄漏了。解决办法是把Base析构函数声明为virtual。这道题在奇安信的笔试题里出现过变体,面试时也经常被追问。
STL容器迭代器失效
vector在push_back触发扩容后,所有迭代器都会失效;erase删除元素后,被删元素之后的迭代器也失效。map和set的插入删除则不会让其他迭代器失效,因为底层是红黑树。
这类题考的是对容器底层实现的理解。虽然选择题只是判断对错,但背后是内存布局和数据结构原理。
2.3 数据结构的典型代码题与高频算法模版
编程题部分,2020年这套题出现了字符串处理、链表操作和二叉树遍历相关的内容。我更建议大家按"模板+变体"的方式准备,而不是盲目刷题。
字符串处理模板
安全方向对字符串处理特别看重,因为很多漏洞都是字符串操作不当引起的。笔试编程题里,字符串反转、字符串去重、判断回文是出现率最高的。
核心思路是双指针。比如反转字符串,一个指针从头,一个指针从尾,交换后向中间移动:
void reverseString(std::string &s) { int left = 0, right = s.size() - 1; while (left < right) { std::swap(s[left], s[right]); ++left; --right; } }链表操作模板
快慢指针找中间节点、判断链表是否有环、反转链表,这三个是必背的。其中反转链表建议掌握迭代和递归两种写法,面试时很可能要求你两种都写一遍。
二叉树遍历模板
前序、中序、后序的递归写法一定要熟到肌肉记忆,非递归写法至少掌握一种。笔试如果出二叉树相关题目,多半是遍历的变体,比如求二叉树最大深度、层序遍历。这些用BFS模板可以统一解决。
提示:奇安信的编程题往往和常见LeetCode题不完全一样,会在场景上做包装。比如不直接考"反转链表",而是给一个日志记录链表,要求把时间戳逆序输出。但本质还是那套东西,识别出来就好办。
3. 网络与系统基础:那些被低估的得分点
3.1 安全公司考网络,不只是背协议
普通互联网公司考网络,一般问到三次握手、四次挥手就差不多了。奇安信不一样,它会往下追问:序列号是怎么初始化的?SYN Flood攻击的原理是什么?为什么TCP要 TIME_WAIT 状态?
因为这些不是单纯的网络理论,它们直接跟安全防护相关。天擎要做入侵检测,要分析网络流量,开发人员如果只懂怎么调socket API,不理解协议底层,根本没法写检测引擎。
2020年的题目里,选择题考了TCP三次握手中SYN标志位和ACK标志位的变化,简答题考了TCP和UDP的区别以及各自的应用场景。这些看起来是基础题,但得分率并不高。
3.2 HTTP协议与Web安全的关系
HTTP是Web安全的基础,奇安信的笔试一定会涉及。需要掌握的内容包括:
- HTTP请求方法以及各自语义(GET、POST、PUT、DELETE、OPTIONS等)
- 状态码的分类和常见含义(200、301、302、400、401、403、404、500、502、503)
- 请求头、响应头的常见字段(Host、User-Agent、Content-Type、Set-Cookie、Location等)
- Cookie和Session的区别与联系
- HTTPS的握手流程,以及证书的作用
这里有个容易被忽视的点:很多同学记得HTTPS用了RSA密钥交换,但2020年的题目更细化,会问你整个握手过程中客户端和服务端分别用哪个密钥加密数据。答案是:会话密钥由客户端生成,用服务端的公钥加密传输,之后双方用会话密钥进行对称加密通信。
3.3 进程、线程与内存管理
操作系统部分的重点,我总结为三块:进程线程模型、内存管理、死锁与并发。
进程线程模型
进程是资源分配的基本单位,线程是调度的基本单位。同一进程内的线程共享地址空间,但各有独立的栈和寄存器上下文。这道题必考,而且经常以"进程和线程的区别"的简答题出现。
内存管理
分段和分页、虚拟地址到物理地址的映射、页面置换算法、堆和栈的区别,这些都要很熟。奇安信的笔试和面试特别喜欢考"堆和栈的区别",因为它跟安全直接相关——缓冲区溢出漏洞利用的就是栈的结构。
死锁与并发
死锁产生的四个必要条件,以及如何避免死锁。信号量和互斥锁的区别。这些是选择题和专业题里的常客。
注意:2020年这套笔试题里的操作系统部分,风格偏向实际应用,不是死记硬背概念。比如会问"多线程同时读写同一个变量,如何保证线程安全",这种问题没有唯一答案,关键是考察你有没有真正写过并发代码、知不知道互斥锁、原子操作、读写锁这些工具。
4. 安全基础与"反直觉"题目:拉开差距的地方
4.1 什么是安全开发工程师的"安全基础"
普通公司的开发笔试,不会要求你懂漏洞原理,但奇安信会。这里说的安全基础,不是让你变成渗透测试专家,而是要掌握以下内容:
- 常见Web漏洞原理:SQL注入、XSS、CSRF、SSRF、文件上传、路径遍历
- 经典二进制漏洞原理:缓冲区溢出、整数溢出、格式化字符串(了解级别)
- 加密算法:对称加密(AES、DES)、非对称加密(RSA)、哈希算法(MD5、SHA-1、SHA-256),以及它们的适用场景
- 安全编码习惯:输入校验、输出编码、最小权限、避免使用不安全的函数
4.2 题目示例:路径遍历、防卸载、进程自我保护
2020年这套题里面,有些题目非常"奇安信",跟热词里面出现的"输入验证:路径遍历""奇安信天擎卸载"等现象其实是一条线。
比如路径遍历的题目,会给你一段代码,要求你判断是否存在路径遍历漏洞,以及如何修复。典型代码如下:
def read_file(filename): base_dir = "/var/data/" full_path = os.path.join(base_dir, filename) with open(full_path, 'r') as f: return f.read()乍一看用了os.path.join,似乎没问题。但如果传入的filename是"../../etc/passwd",os.path.join会返回"/var/data/../../etc/passwd",也就是"/etc/passwd"。这就是路径遍历漏洞。
修复方式有两个方向:一是对filename做规范化处理之后,检查结果是否以base_dir开头;二是使用白名单校验,只允许文件名匹配特定的安全模式。
这个考点不是随便出的,它对应的是真实产品的输入校验需求。奇安信的开发者在写文件访问功能时,面对的就是这类问题。
再比如,热词里大量出现的"奇安信天擎卸载要密码""防卸载"这类现象,本质上对应着一个真实的安全需求:安全软件必须防止恶意程序或用户误操作把自己卸载掉。实现方式包括:
- 进程自我保护,通过驱动层hook系统调用,阻止对进程的终止操作
- 文件与注册表保护,阻止对核心文件和自启动项的修改
- 卸载鉴权机制,要求用户提供管理员密码或验证码,防止未授权卸载
笔试不会直接考"怎么给天擎加卸载密码",但会以"如何设计一个自我保护机制"这类开放性问题出现。如果你了解一点驱动层面的技术,比如SSDT Hook、内核回调、文件系统过滤驱动,答题时就能写出比别人更专业的内容。
4.3 怎么短期准备安全基础知识
如果你不是安全专业的,临时补安全知识时间肯定来不及。我的建议是抓大放小:
- Web漏洞原理花两天时间,各写一遍攻击payload和防御代码
- 加密算法重点理解AES和RSA的区别,以及HTTPS里怎么配合使用
- 安全编码习惯重点记住"永远不要信任外部输入"
- 路径遍历、SQL注入、XSS这三种漏洞的原理和修复方法,必须熟练掌握
其他的二进制漏洞、逆向工程、恶意代码分析等内容,笔试选择题可能会涉及概念,但不会让你真的去分析木马。了解名词和基本原理就够了。
5. 笔试代码实战:从暴力解到最优解的提分路径
5.1 时间分配与题目顺序策略
我帮人改过不少笔试代码,发现一个问题:很多人喜欢死磕编程题,结果选择题没时间做,简答题草草写两行。这是非常错误的策略。
我的建议是:先做选择题,控制在40分钟以内,遇到不会的果断标记跳过,不要纠结。然后做简答题,每道10到15分钟。最后剩下40到60分钟做编程题。
编程题如果卡了超过20分钟,先写一个暴力解法拿部分分,然后优化。笔试系统通常按测试用例给分,暴力解法能过20%到40%的用例,总比交白卷强。
5.2 高频代码题的解题模板
针对2020年这套题的具体情况,我再补充两个实际出现过的题目类型。
类型一:字符串压缩
题目会给一个字符串,比如"aabcccccaaa",要求压缩成"a2b1c5a3"。如果压缩后的字符串不比原串短,就返回原串。
这题本身不难,但很多人忽略了一个关键点:压缩后的字符频率可能超过9,比如连续100个'a',需要写成"a100",而不是"a9"加"9"。
std::string compressString(const std::string &s) { std::string result; int i = 0; while (i < s.size()) { int j = i; while (j < s.size() && s[j] == s[i]) { ++j; } result.push_back(s[i]); result += std::to_string(j - i); i = j; } return result.size() < s.size() ? result : s; }类型二:合并两个有序链表
这是单链表里的经典题。迭代写法用哑节点,递归写法更简洁。奇安信笔试把它拿来做编程题,考的是基本功扎不扎实。
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { ListNode dummy(0); ListNode *tail = &dummy; while (l1 && l2) { if (l1->val < l2->val) { tail->next = l1; l1 = l1->next; } else { tail->next = l2; l2 = l2->next; } tail = tail->next; } tail->next = l1 ? l1 : l2; return dummy.next; }5.3 边界条件与异常输入:面试官真正想看的东西
编程题不是跑通就完了,代码的健壮性同样重要。奇安信的笔试系统会跑隐藏测试用例,专门测边界条件。
常见的边界条件包括:空字符串、单字符字符串、链表只有头节点、输入为nullptr、数值溢出的情况。写代码时,多花十秒钟想一下这些情况,比盲目追求花哨算法值钱得多。
另外,代码风格也很重要。变量命名有语义、缩进规范、关键步骤有注释,这些不会直接加分,但会让面试官在看你笔试代码时印象好很多。
6. 面试现场:如何把项目经历讲成安全故事
6.1 项目包装的核心:从"功能实现"到"安全思考"
笔试过了之后,面试是另一道坎。奇安信的技术面试有一个很鲜明的特点:面试官会深挖你的项目经历,而且不是问"你做了什么",而是问"你踩过什么坑""你考虑过哪些安全风险"。
举个例子,如果你简历上写了"用一个Web框架开发了某某管理系统",普通公司面试官会问框架用法,奇安信面试官可能会问:你的登录功能是怎么实现的?密码存的是明文还是哈希?如果用户输入了SQL语句怎么办?你这个系统的文件上传功能有没有限制文件类型?
所以,面试前要把自己做过的项目,从安全角度重新过一遍。哪怕只是学校的课程设计,也需要讲清楚:
- 输入数据有没有做校验?具体校验了什么?
- 有没有处理权限控制?越权访问是怎么防止的?
- 数据存储有没有加密?密码是什么方式存放的?
- 如果有用户上传文件,做了哪些防护?
这些问题不一定要求你做得完美,但你必须想过。哪怕回答"当时没想到,现在觉得应该这样做",也远好过"没考虑过这个问题"。
6.2 常见面试追问与应答逻辑
我总结了几类奇安信面试官常问的追问方式,供参考。
追问一:场景设计
"如果让你设计一个日志分析系统,你会怎么做?"
这种问题没有标准答案,考察的是你的设计思路和表达能力。回答的框架是:先从需求出发,说清楚要分析什么、数据量多大、实时性要求多高,然后再说技术选型,比如采集用Agent还是直接读文件、存储用ES还是ClickHouse、计算用Spark还是Flink、告警怎么触发。
追问二:底层原理
"TCP为什么需要三次握手,两次行不行?"
这种问题的回答逻辑是:先复述基本原理,再说如果只有两次握手会发生什么,最好能结合具体的异常场景。比如两次握手会导致服务端无法确认客户端的接收能力,可能出现已失效的连接请求到达服务端,导致资源浪费。
追问三:安全攻防
"如果被流量攻击,你会怎么防御?"
这种题考察的是你有没有从攻防视角思考问题的习惯。基本回答思路包括:先做流量清洗、限流,再分析攻击特征、封禁源IP,再从架构层面做高可用、负载均衡,最后是应急响应和溯源。如果能提一下具体的技术方案,比如用Nginx做连接数限制、用防火墙做规则匹配、用WAF拦截应用层攻击,会更有说服力。
追问四:算法优化
"你刚才说这个模块的性能有瓶颈,具体是哪里,怎么优化的?"
这种问题考察的是你有没有真实的性能调优经验。回答时要给出具体的数据:优化前多少毫秒,优化后多少毫秒,瓶颈在哪,做了什么改动。哪怕优化幅度不大,只要有真实数据,都算合格。
6.3 个人备考时间线与建议
最后说说时间安排。如果你离笔试还有三到四周,可以这样分配:
- 第一周:把C/C++基础过一遍,重点是指针、内存、STL,加上常见数据结构的代码题
- 第二周:复习计算机网络和操作系统,每天刷20道选择题,保持手感
- 第三周:补安全基础,每天花两小时看Web漏洞原理和安全编码规范
- 第四周:集中做套题,模拟笔试环境,训练时间分配
如果只有一周,优先做三件事:背C/C++高频考点、刷熟三个编程题模板(字符串、链表、二叉树)、整理一份自己的"安全基础笔记"。
另外,笔试前一定要熟悉奇安信的笔试系统。有的系统支持本地编译器调试,有的只支持在线编辑。提前用在线编辑器写几道题,练一练代码补全不依赖IDE的感觉,不然笔试时会非常难受。
我在实际带新人的过程中发现,那些能过笔试的人,并不是最聪明的,而是准备方向最对的。奇安信这类安全厂商考的不只是算法,更是你对系统底层和安全原理的理解。把这些基础打扎实了,面对笔试题目时,你会发现大部分题都是换了个壳的熟悉考点。最后再分享一个小技巧:刷题时遇到不会的简答题,不要空着。把你理解的原理写上去,哪怕不完全对,也比白卷强。笔试阅卷是按点给分的,多写一个要点,就多一分希望。
