ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

奇安信前端笔试题复盘:基础、框架与安全思维全解析

奇安信前端笔试题复盘:基础、框架与安全思维全解析 做安全业务的前端工程师和做电商、后台管理系统的前端工程师面试考察的重点确实不太一样。前阵子好几个准备春招的学弟学妹来问奇安信前端开发试题怎么准备网上能找到的版本都比较碎片化不是只贴了几道题就是答案有歧义甚至干脆是错的。我结合近几年奇安信以及其他安全厂商前端岗位的实际面试题和我的辅导经验把这批试题涉及的知识点、答题思路和容易掉进去的坑完整复盘一遍既是给准备投安全领域前端岗位的同学参考也是给日常做 Web 开发的朋友提个醒安全思维放在前端工程里绝不是嘴上说说那么简单。这篇文章按照“题型分布—基础题精讲—框架与工程化—安全特色题—备考路线”的逻辑来写其中穿插了大量真实答题过程中容易踩的细节。无论你是准备春招秋招的应届生、想跳槽到安全产品线的前端工程师还是想了解安全厂商如何考察前端能力的技术 leader应该都能从中找到有价值的信息。1. 安全厂商前端笔试究竟在考什么1.1 技术栈画像为什么不是纯算法而是全栈工程题先说一个很多人会误解的点。看到“奇安信”这个名字很多同学第一反应是“安全公司那前端笔试会不会考渗透、考加密算法、考二进制逆向”。实际上前端岗位的笔试题目主要还是围绕前端工程本身展开安全相关内容更像“隐藏关卡”一样渗透在系统设计题和代码实现题里。2019 年春招这批题目给我的整体观感是它考的不是你会不会写某个 API而是你能不能在一个有安全约束的真实业务场景中写出可维护、可扩展、不出安全事故的前端代码。从技术栈画像上看奇安信这类安全厂商的前端团队和一般互联网公司前端团队的区别在于业务系统多为数据可视化大屏、态势感知控制台、漏洞管理平台SPA 应用居多Vue 和 React 都有2019 年那个时间点 Vue 的比例明显更高对工程化的要求很高Webpack 配置、构建优化是必问题对 HTTP、浏览器缓存、网络安全模型的理解深度要求高于普通 To C 业务团队。所以笔试题目并不是剑走偏锋而是在基础题之上叠加了“安全业务”特有的约束条件。你可以把这份试题理解成70% 是常规前端基础30% 是安全场景下的前端工程能力考察。1.2 知识点分布从真题归纳出的高频考点占比结合 2019 春招多批次的题目复盘我按照题型和知识点做了个粗略统计。因为不是官方精确数据仅供复习时排优先级用但覆盖度足够说明问题。知识点模块大概占比典型考察形式JavaScript 基础作用域、闭包、异步20%读代码写输出、手写实现浏览器与网络渲染流程、缓存、HTTP15%简答、流程描述CSS 与布局10%代码实现题Vue 框架原理与组件通信20%原理简答 场景题Webpack 与工程化10%配置题、构建优化题前端安全XSS、CSRF、CSP、HTTPS15%安全分析题、代码审计题手写算法与编程题10%数组、字符串、简单数据结构也就是说纯粹的“算法题”占比并不高更不会出现 LeetCode Hard 级别的题目。真正决定你能不能过笔试的是基础题的正确率和安全场景题的逻辑严密性。很多同学挂在笔试上不是因为算法不会写而是因为基础概念答得不严谨安全题完全没概念。2. 核心基础题逐题精讲从题意到答案框架2.1 JS 作用域与异步一道题串起调用栈、微任务和闭包这种题在奇安信的试卷里几乎是必出的形式一般是“读代码写出输出顺序”然后附带一两小问。下面这道题是比较有代表性的版本我根据回忆做了还原考点覆盖很全面for (var i 0; i 5; i) { setTimeout(() { console.log(i); }, 0); } console.log(start); Promise.resolve().then(() { console.log(promise1); });如果对事件循环不够熟很容易直接答“0 1 2 3 4 start promise1”。实际上输出顺序应该是start promise1 5 5 5 5 5这道题至少有四个隐藏考点第一var声明的i是函数作用域for循环结束后i已经变成 5所有setTimeout回调拿到的都是同一个变量。想输出 0 1 2 3 4得用let或者用 IIFE 制造闭包。第二宏任务和微任务的执行顺序。setTimeout是宏任务Promise.then是微任务。同一轮事件循环里微任务队列会先于宏任务队列执行所以promise1会排在所有setTimeout之前。第三即使setTimeout的延迟写的是 0它也要等到当前调用栈清空后才能执行所以start最先输出。第四如果面试官追加问一句“如果setTimeout换成setInterval会发生什么”你要能想到”回调执行时间受事件循环拥堵影响firing interval 不一定精确“这个层面。这种题的答题策略是先把结论按顺序列出来再逐行解释执行过程不要只写答案。阅卷人看的是你的思考链路是否清晰。2.2 数组与对象操作常考变体与隐藏扣分点奇安信笔试里的手写编程题不会太难常见的有数组去重、深拷贝、防抖节流、数组扁平化。但“简单”不意味着容易拿满分因为阅卷时非常看重边界处理。以数组去重为例大多数人能写出Array.from(new Set(arr))但如果题目要求“在不使用 Set 的前提下实现并且能区分 1 和 1”情况就不一样了。标准答案有两个层次// 第一层利用对象 key 去重但要注意类型区分 function unique(arr) { const map Object.create(null); const result []; arr.forEach(item { const key typeof item _ item; if (!map[key]) { map[key] true; result.push(item); } }); return result; }这版答案把类型信息拼进 key就能区分1和1。加分版本还会讨论NaN的去重问题NaN NaN是 false但大多数去重需求希望 NaN 只保留一个。你可以追加判断如果item ! item且结果数组中还没有 NaN就直接 push。再来看深拷贝这道题出现频率也很高。很多人会写JSON.parse(JSON.stringify(obj))然后在丢分点处暴露问题丢undefined、函数、Symbol 类型的属性无法处理循环引用直接栈溢出特殊对象如Date、RegExp会被转成字符串或空对象BigInt会直接抛异常。所以如果笔试时间允许尽量手写一个递归版本至少把“普通对象 数组 Date 循环引用”这四层处理掉。下面是一个够用的参考实现function deepClone(obj, map new Map()) { if (obj null || typeof obj ! object) { return obj; } if (obj instanceof Date) { return new Date(obj.getTime()); } if (obj instanceof RegExp) { return new RegExp(obj.source, obj.flags); } if (map.has(obj)) { return map.get(obj); } const clone Array.isArray(obj) ? [] : {}; map.set(obj, clone); Object.keys(obj).forEach(key { clone[key] deepClone(obj[key], map); }); return clone; }这里用map记录已经克隆过的对象循环引用就不会爆栈了。数组扁平化也有多种考法数字版本用flat(Infinity)一行搞定但如果要求手写建议用reduce concat递归实现function flat(arr) { return arr.reduce((acc, cur) { return acc.concat(Array.isArray(cur) ? flat(cur) : cur); }, []); }这类题最大的教训是不要追求炫技先把最稳的写法写出来再补边界说明。2.3 布局与浏览器渲染20 分钟内出可用代码的诀窍CSS 题在安全厂商笔试里占比不高但考得非常实用。最常见的是“左固定右自适应”和“垂直水平居中”。2019 年这批题目里还出现过一道很接地气的题写一个两栏布局左侧宽度 200px右侧占满剩余空间并且要求右侧内容可以独立滚动。现代解法当然是 flex 一把梭.container { display: flex; height: 100vh; } .left { flex: 0 0 200px; height: 100%; overflow-y: auto; } .right { flex: 1; height: 100%; overflow-y: auto; }但在笔试中如果只写 flex 方案有些阅卷人会追问“如果不支持 flex 怎么办”。这时候你要能补出 float 或绝对定位的版本。浮动版本注意清除浮动绝对定位版本注意给右侧加margin-left: 200px并且父容器设position: relative。垂直水平居中也是高频题我建议把三种思路都准备好flex 方案display: flex; align-items: center; justify-content: center;、grid 方案place-items: center、绝对定位加负 margin 或 transform 方案。每种方案的适用场景和兼容性都心里有数答题时主动写出来会比只写一种方案强很多。这里有一个答题技巧遇到布局题先把盒模型和文档流说清楚再写代码。比如提到“flex 布局的本质是改变display的计算值让子元素进入 BFC 上下文”这种表达会显得你真的理解布局原理而不是背了几行 CSS。3. 框架与工程化Vue/Webpack 题型的答题节奏3.1 Vue 响应式原理别只背数据劫持奇安信笔试里的 Vue 题占了不少比重最常考的就是响应式原理。很多同学能背出“Object.defineProperty 劫持数据发布订阅模式更新视图”但一到追问就露馅。答题框架我给一个比较完整的版本你可以按这个层次展开第一层Vue 2 的响应式核心是Object.defineProperty通过getter收集依赖通过setter触发更新。每个对象都会通过observer方法递归遍历所有属性。第二层每个响应式属性都有一个Dep实例依赖收集器组件渲染时访问数据会触发getter把当前Watcher收集进Dep。数据变化时触发setter通知所有收集到的Watcher执行回调。第三层组件对应一个Watcher用户手动$watch也会创建Watcher。更新是异步批量的数据变化先用queueWatcher把 Watcher 推进队列再用nextTick在微任务里统一更新。第四层Object.defineProperty的局限。数组的push、pop等方法无法拦截所以 Vue 2 要重写数组原型方法新增属性无法劫持所以需要Vue.set。Vue 3 改用Proxy后这些问题才能从根上解决。如果笔试时能写出前三层你已经超过大多数人了如果能主动提到第四层局限阅卷人会觉得你踩过坑这是很大的加分项。3.2 组件通信题先做分类再选方案另一个高频考点是组件通信。典型题目是“父组件需要监听子组件内部按钮点击事件并传一个对象给子组件配置展示子组件修改后要通知父组件。”这种场景题如果只答“用 props 和 $emit”得分不会高因为面试官想看到的是你对通信方案的全景认知。我的建议是先分类再选方案通信场景推荐方案说明父子通信props 下行$emit 上行思想是单向数据流避免子组件直接改 props兄弟通信事件总线 EventBus / 状态管理项目小可以用 EventBus项目大建议 Vuex跨层级通信provide/inject适合深度嵌套但要控制使用范围任意组件Vuex / Pinia全局状态集中管理适合复杂业务答题时还要多说一句“为什么不用 XXX”。比如有人问为什么不用$parent和$children你得知道它的问题是组件层级变化时脆弱、难以追踪不适合维护。这道题还有一个高阶版本“父组件直接改子组件 props 里的对象属性子组件怎么感知”隐藏考点是 props 的浅监听与深度变化。对于深层对象属性的修改子组件里如果用的是watch监听整个 prop 对象默认不开启deep是监听不到变化的。想响应变化需要watch: { obj: { handler, deep: true } }或者直接按对象地址变化来设计数据流。3.3 Webpack 优化常规答案与加分答案的区别Webpack 相关的题目常见的有“构建速度慢怎么优化”“打包体积过大怎么优化”。奇安信的题目更偏实际工程会给你一个具体场景一个管理后台项目首屏加载 5 秒你怎么下手。常规答案一般是路由懒加载代码分割 splitChunks图片压缩去掉 sourceMap。这些答案没错但过于模板化。加分答案要体现你的排查顺序和量化意识。现在很多面试官喜欢听“先量化再优化”套路可以是先用webpack-bundle-analyzer看产物模块体积分布锁定体积最大的几个包检查是否存在重复打包比如多个包依赖了同一份 lodash但 chunk 没合并对第三方库启用 CDN 或 DllPlugin 预编译配置splitChunks把 node_modules 中的基础库单独拆成vendorchunk长期缓存关掉不必要的devtool生产环境使用source-map或hidden-source-map而不是cheap-module-eval-source-map利用cache-loader或babel-loader的cacheDirectory加速二次构建。答到第 3、4 步已经很扎实了第 5 步能看出你对生产配置的细节有把握。如果还能补一句“优化之后要用 performance 面板对比 Lighthouse 分数”就完全是工程实践的思路了。4. 安全公司面试题的“隐藏题”前端安全思维4.1 你会如何处理不信任的用户输入奇安信这类安全厂商的笔试题一定会出现前端安全相关的题目。有些是明着考直接问“什么是 XSS”有些是藏在场景题里。2019 年春招有一道印象深刻的题给你一个搜索页用户输入关键词后前端拿到后端返回的搜索结果并渲染到页面上请写出这个过程的完整实现并指出存在哪些安全风险。正常实现人人都会重点在后半句。这道题的安全考点大致如下用户输入的内容不能直接插入innerHTML尤其是搜索关键词这种回显场景如果后端不转义恶意输入img srcx onerroralert(1)会直接执行展示搜索结果时优先使用textContent而不是innerHTML如果必须要用v-html必须对内容做白名单过滤或转义后端接口返回的数据也不能轻信如果接口被劫持或后端被脱库返回的恶意脚本一样会执行前端要校验输入长度和特殊字符但注意这不能替代后端校验前端校验只是为了提升体验和减少无效请求。这道题的完整答题框架可以总结成“输入—传输—渲染—执行”四个环节每个环节分别说明风险与对策。这种结构化的表达非常加分说明你不是背题而是有完整的威胁建模意识。4.2 一个 XSS 漏洞定位题的完整分析路径还有一类题目是给一段有漏洞的代码让你指出漏洞并修复。我印象里考过一段典型代码function renderComment(comment) { const dom document.getElementById(comments); dom.innerHTML div classcomment comment.content /div; }漏洞很明显comment.content被无转义拼进innerHTML。修复方式有以下几种按推荐程度排序改用textContent或innerText让内容不再被当成 HTML 解析如果是富文本场景先用白名单过滤器清洗 HTML保留安全的标签和属性再渲染使用前端框架的插值语法如 Vue 的{{ }}框架默认会转义但要避免用v-html。答题时还需要指出这条漏洞的触发链路攻击者在评论框提交script或事件属性存储到后端其他用户打开页面时后端返回恶意内容前端拼接 HTML 导致脚本执行。这属于存储型 XSS。这种题目如果能画一条完整链路——输入、存储、渲染、执行——再给出修复代码很容易拿高分。注意答题中不要只修一处要同时考虑“前端转义”和“后端转义/过滤”两道防线因为攻击者可以绕过前端直接构造请求。4.3 CSP 与 HTTPS如何把安全能力落实到工程配置安全厂商笔试还会考一些偏“工程化安全”的知识比如 CSPContent Security Policy。有些同学完全没接触过拿到题一脸懵。其实 CSP 的原理很简单通过 HTTP 响应头告诉浏览器“页面只能加载来自哪些来源的资源、脚本能否执行”从而在源头上降低注入攻击的影响面。答题的关键是说清层级而不是只背一个 Header 语法。比如配置Content-Security-Policy: default-src self; script-src self unsafe-inline https://cdn.example.com; style-src self unsafe-inline; img-src self data:;这里每一项都对应一类资源default-src是兜底策略script-src限制脚本来源style-src限制样式来源img-src限制图片来源。把script-src设置成self可以基本杜绝外域脚本注入unsafe-inline虽然会削弱防护但在某些业务中不得不用要理解它的代价。再比如 HTTPS 相关的题常见问法是“为什么前端要关注 HTTPS”。除了“加密传输防窃听”更前端的落地点是混合内容问题HTTPS 页面加载 HTTP 的脚本、图片、接口请求会被浏览器拦截或告警Service Worker 和 PWA 必须在 HTTPS 下才能注册navigator.geolocation、navigator.clipboard等 API 对非安全上下文有限制之前提到的 CSP、Strict-Transport-Security、Feature-Policy等安全响应头大部分都要依赖 HTTPS 生效。如果笔试中出现“如何配置 HSTS”这种题答出“响应头Strict-Transport-Security: max-age31536000; includeSubDomains; preload并解释preload的含义”就够了。如果你能主动指出“HSTS 最大的坑是第一次访问是 HTTP需要通过 301 跳转否则 HSTS 也保护不了第一次请求”这个深度会非常加分。5. 真题复盘后的备考路线与踩坑提醒5.1 备考重点排序按得分性价比安排复习如果你现在离笔试还有两三周我不建议从零开始把 Vue 源码、Webpack 源码、算法题全刷一遍性价比太低。比较合理的备考顺序是这样的第一优先级把 JavaScript 基础概念彻底过一遍。作用域、闭包、原型链、事件循环、this 指向、Promise。这些题目出现频率最高而且稳定拿分。复习方式是“先做题验证再回去翻书”不要光看书觉得自己懂了。我见过很多同学“闭包”背得滚瓜烂熟遇到for(var i...)输出题还是错说明根本没有建立运行模型。第二优先级Vue 核心原理和常见面试题。响应式、生命周期、组件通信、nextTick、computed与watch的区别、v-if与v-show的区别。这部分背题有用但要能结合具体代码解释。第三优先级安全类题。优先级没有前两个高但对奇安信来说非常关键。至少把 XSS、CSRF、CSP、HTTPS、同源策略这五个概念搞懂并能各自说出一段“项目里怎么防护”的实践。第四优先级Webpack 和浏览器原理。不用挖太深但要能说清楚概念、区别和常用配置。最后才是算法题掌握数组、字符串、树的前中后序遍历、二叉树的层级遍历就够应付大多数笔试了。如果时间不够LeetCode 刷 Hot 100 前 50 题就行不用追求难度。5.2 笔试题特别容易丢分的 4 个细节说一下我批改类似笔试题时经常看到的问题这些都是实打实的丢分项。第一只写答案不写过程。有些代码题比如读代码输出你直接写一个数字序列即使对了也可能被扣分因为阅卷人没法判断你是推理出来的还是蒙的。合理做法是先用文字简述执行步骤比如“第一轮调用栈开始时输出 start然后微任务队列执行 promise1最后宏任务执行 setTimeout 回调”再给出结论。第二代码书写极不规范。缩进混乱、变量命名随意、没有分号、中文注释里出现错别字这些都会影响观感。笔试阅卷时一份代码清晰度和一份代码混乱但结果相似的卷子得分差距可能达到两三分以上。请注意笔试中的代码是要给人看的。第三不做边界处理。手写深拷贝、数组去重、防抖节流时不处理参数为 null 或 undefined 的情况不处理空数组的情况。哪怕侥幸过了用例也会在追问中露馅。动手前先在代码里加两行if (!arr || arr.length 0) return []之类的保护专业感会明显提升。第四遇到不会的安全题空着不写。安全厂商笔试里安全题不是只有非黑即白的对错你哪怕不知道完整答案如果能写清楚威胁场景和基本对策的框架也会得到部分分数。空着是最亏的。5.3 从笔试到技术面试的追问逻辑笔试过了之后面试官大概率会围绕你笔试时的答案展开追问。比如你笔试里写了深拷贝实现面试官会问“如果对象里有函数你这版怎么处理”“循环引用你怎么解决的”“为什么用 Map 存克隆记录能不能用 WeakMap”。这就是为什么我强调笔试时不要堆砌网上抄来的高深答案一定要亲手把每行代码都理解到位。你写在卷子上的每一句话都可能成为面试时的追问对象。应对追问的通用方法是准备一个“项目里的安全工程实践”故事。比如“我之前负责的页面要对用户输入内容做展示曾遇到 XSS 的风险我的处理方式是前端用v-html前先经过白名单过滤后端同步做转义并且配置了 CSP 响应头禁止外域脚本加载”。这个故事既能展示安全意识又能展示解决问题的能力比满口理论管用得多。另外如果你投的是奇安信这类安全厂商简历上如果写过“熟悉前端安全”一定要真的能答上来至少五个具体安全知识点。被问到不会还硬答比老老实实说“这块我还没来得及深入了解”更伤。写到这里回想我自己当年整理前端面试题的过程最大的感悟是面试题不是终点而是帮你查漏补缺的镜子。安全厂商的题目之所以值得复盘是因为它把“工程能力”和“安全素养”揉在一起考察比单纯刷算法题更能反映一个前端工程师的综合水平。如果你正打算投安全领域的前端岗位建议把这篇文章里涉及的知识点全部过一遍并且每道题都亲手写一遍代码。多花点时间在原理上少背点网上的标准答案笔试和面试都会稳得多。
返回列表