面试官问到web安全你知道前后端怎么处理吗

web安全在软件开发中一般在运维与业务服务层已经做了过滤与兜底行为,但作为前端我们还是需要知道并主动参与到安全防范中,尽可能在全链路上去识别和避免出现安全问题。常见的Web安全问题包括跨站脚本攻击(XSS)、跨站请求伪造(CSRF)、SQL注入、会话劫持、不当的身份验证和授权等。

1. 跨站脚本攻击(XSS)

XSS攻击是指攻击者通过在网页中注入恶意脚本 ,使其在用户浏览器中执行,并获取用户敏感信息。为了防止XSS攻击,可以进行输入验证和输出转义,确保用户输入的内容不会被当作脚本执行。

前端

在Web应用的前端,可以对用户输入进行过滤和转义,确保输入内容不会被解释为恶意脚本。例如,使用JavaScript的innerTexttextContent属性来插入文本内容,而不是使用innerHTML。如以下的代码片段,展示了未经过滤的用户输入如何导致XSS攻击:

假设有一个简单的留言板功能,用户可以在留言中输入内容并将其显示在页面上。

javascript 复制代码
function displayMessage(message) {
  const messageContainer = document.getElementById('message-container');
  messageContainer.innerHTML = message;
}

// 获取用户输入的留言
const userMessage = document.getElementById('user-message-input').value;

// 显示留言
displayMessage(userMessage);

在上述示例中,如果用户输入恶意的JavaScript代码作为留言内容,例如 <script>alert('XSS Attack!');</script>,那么该恶意代码将直接被插入到页面的HTML结构中,导致XSS攻击。

可能的行为表现:

  • 在页面上弹出一个警报框,显示了恶意脚本中包含的文本信息,例如 "XSS Attack!"。
  • 攻击者可以利用这个XSS漏洞,执行任意的JavaScript代码,进行跨站请求伪造(CSRF)、窃取用户Cookie等恶意操作。

要防止XSS攻击,前端应该对用户输入进行正确的过滤和转义,确保任何用户提供的内容都不会被解析为可执行的代码。以下是修改后的示例代码,使用内置的转义函数来防止XSS攻击:

javascript 复制代码
function displayMessage(message) {
  const messageContainer = document.getElementById('message-container');
  messageContainer.textContent = message; // 使用textContent而不是innerHTML
}

// 获取用户输入的留言
const userMessage = document.getElementById('user-message-input').value;

// 转义用户输入,防止XSS攻击
const sanitizedMessage = escapeHtml(userMessage);

// 显示留言
displayMessage(sanitizedMessage);

// 转义HTML字符的辅助函数
function escapeHtml(text) {
  const element = document.createElement('div');
  element.textContent = text;
  return element.innerHTML;
}

后端

在后端,可以使用库来过滤和转义用户输入,以防止XSS攻击。以下是一个使用xss库在后端进行XSS防御的示例代码:

javascript 复制代码
   const express = require('express');
   const xss = require('xss');

   const app = express();

   app.post('/submit', (req, res) => {
     const userInput = req.body.input;
     const sanitizedInput = xss(userInput); // 使用xss库进行输入转义
     // 处理用户输入...
   });

   app.listen(3000, () => {
     console.log('Server started on port 3000');
   });

2. 跨站请求伪造(CSRF)

CSRF攻击是指攻击者利用用户已登录的身份执行恶意请求。为了防止CSRF攻击,可以使用CSRF令牌(也称为同步令牌)来验证请求的合法性。

前端

在Web应用的前端,可以通过生成并使用CSRF令牌来防止CSRF攻击。将CSRF令牌包含在每个请求中,以验证请求的合法性。例如,在表单中添加隐藏字段来存储CSRF令牌,并在提交表单时将其发送到后端。

假设有一个简单的博客发布功能,用户可以在页面上输入标题和内容,并通过POST请求将其发布到服务器。

javascript 复制代码
function publishBlog(title, content) {
  const xhr = new XMLHttpRequest();
  xhr.open('POST', '/publish', true);
  xhr.setRequestHeader('Content-Type', 'application/json');

  const data = {
    title: title,
    content: content
  };

  xhr.send(JSON.stringify(data));
}

// 获取用户输入的标题和内容
const userTitle = document.getElementById('title-input').value;
const userContent = document.getElementById('content-input').value;

// 发布博客
publishBlog(userTitle, userContent);

在上述示例中,如果用户同时登录了钓鱼网站,并在该网站上触发了一个恶意请求,该请求被设计成向博客发布接口发送POST请求,攻击者可以利用用户的身份在用户不知情的情况下发布恶意内容。

要防止CSRF攻击,可以通过添加CSRF令牌来验证请求的来源。以下是修改后的示例代码,添加了CSRF令牌的验证:

javascript 复制代码
function publishBlog(title, content, csrfToken) {
  const xhr = new XMLHttpRequest();
  xhr.open('POST', '/publish', true);
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.setRequestHeader('X-CSRF-Token', csrfToken); // 添加CSRF令牌

  const data = {
    title: title,
    content: content
  };

  xhr.send(JSON.stringify(data));
}

// 获取用户输入的标题和内容
const userTitle = document.getElementById('title-input').value;
const userContent = document.getElementById('content-input').value;

// 获取CSRF令牌
const csrfToken = document.getElementById('csrf-token').value;

// 发布博客
publishBlog(userTitle, userContent, csrfToken);

在上述修改后的代码中,添加了一个名为X-CSRF-Token的请求头,该请求头通过csrfToken参数传递CSRF令牌的值。服务器端应该在接收到请求时验证CSRF令牌的有效性,以确保请求来自合法的来源。

后端

在后端,可以使用库来验证请求中的CSRF令牌,并确保其与会话中存储的令牌匹配。以下是一个使用csurf库在后端进行CSRF防御的示例代码:

javascript 复制代码
   const express = require('express');
   const csrf = require('csurf');

   const app = express();
   const csrfProtection = csrf({ cookie: true });

   app.get('/form', csrfProtection, (req, res) => {
     res.render('form', { csrfToken: req.csrfToken() });
   });

   app.post('/submit', csrfProtection, (req, res) => {
     // 验证CSRF令牌和处理请求...
   });

   app.listen(3000, () => {
     console.log('Server started on port 3000');
   });

3. SQL注入

SQL注入是指攻击者通过在用户输入的数据中插入恶意SQL代码,从而获取、修改或删除数据库中的数据。为了防止SQL注入,可以使用参数化查询或预编译语句,确保用户输入不会被解释为SQL代码。

前端

假设后端代码如下:

js 复制代码
const express = require('express');
const app = express();

// 模拟数据库查询函数
function authenticateUser(username, password) {
  // 模拟数据库查询,拼接SQL查询语句
  const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
  
  // 执行查询...
}

app.use(express.urlencoded({ extended: true }));

app.post('/login', (req, res) => {
  const username = req.body.username;
  const password = req.body.password;

  // 身份验证
  authenticateUser(username, password);

  // 其他逻辑...
});

如果用户在用户名或密码字段中输入恶意内容,例如 ' OR '1'='1,构成的SQL查询语句将变为 SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '' OR '1'='1'

这将使查询条件始终为真,绕过了身份验证,攻击者可能会成功登录或执行其他未经授权的操作。

后端

在后端,可以使用参数化查询或预编译语句来防止SQL注入。以下是一个使用mysql库在后端进行SQL注入防御的示例代码:

javascript 复制代码
const mysql = require('mysql');
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'username',
  password: 'password',
  database: 'database_name'
});

function authenticateUser(username, password) {
  const query = 'SELECT * FROM users WHERE username = ? AND password = ?';
  const values = [username, password];
  
  connection.query(query, values, (error, results) => {
    // 处理查询结果...
  });
}

在上述修改后的代码中,使用了参数化查询,将用户输入的用户名和密码作为查询的参数传递给数据库,避免了SQL注入攻击的风险。

4. 会话劫持

会话劫持是指攻击者获取用户的会话ID,从而冒充用户进行操作。为了防止会话劫持,可以使用安全的会话管理,包括使用HTTPS、设置适当的会话过期时间和使用安全的cookie标记。

前端

在前端,可以使用安全的cookie标记,包括将cookie标记为仅通过HTTP访问和仅在HTTPS下使用。这可以通过设置cookie的httpOnlysecure属性来实现。

后端

在后端,以express为例,可以使用express-session库来管理会话,并设置适当的会话配置,包括secretresavesaveUninitializedcookie。以下是一个使用express-session库在后端进行会话劫持防御的示例代码:

javascript 复制代码
const express = require('express');
const session = require('express-session');

const app = express();

app.use(session({
  secret: 'mySecret',
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,
    secure: true,
  },
}));

app.get('/login', (req, res) => {
  // 验证用户凭据...
  req.session.userId = 'user123'; // 将用户ID存储在会话中
  res.send('Login successful');
});

app.get('/dashboard', (req, res) => {
  const userId = req.session.userId; // 从会话中获取用户ID
  // 获取用户数据并呈现仪表板...
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});

这个示例演示了在登录过程中将用户ID存储在会话中,并在后续请求中使用它来验证用户身份。使用httpOnlysecure属性设置cookie的安全性,可以防止会话劫持攻击。

注意,会话支持的安全问题不仅限于XSS攻击,会话支持还可能面临其他安全问题,如会话劫持、会话固定、会话劫持等。

总结

总的来说,Web安全问题不仅仅是运维或后端开发人员的责任,前端开发人员也扮演着至关重要的角色。希望本文可以让你温故而知新,巩固这方面的知识点,保持学习,共勉~

相关推荐
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb5 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角5 小时前
CSS 颜色
前端·css
九酒6 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔7 小时前
HTML5 新表单属性详解
前端·html·html5
lee5767 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579657 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
limit for me8 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者8 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架