如何设计一个安全可靠的 API 接口?
yuyutoo 2024-10-25 19:20 9 浏览 0 评论
作者 | 阿文
责编 | 屠敏
出品 | CSDN(ID:CSDNnews)
最近几年,随着RESTful API开始风靡,使用HTTP header来传递认证令牌似乎变得理所应当,通过 RESTful 的API 接口设计简化了系统架构, 减少了耦合性, 可以让所有模块各自独立的进行改进。
不过,在实际的REST API 接口设计过程中,我们需要考虑如何让鉴权变得更安全可靠,例如不会被第三方恶意请求或者保证传输过程中的数据安全以及防止重复提交,本文就一起聊一聊。
传统的Session 认证方式
首先,我们说一些传统的认证方式,众所周知,HTTP 协议是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。
而这种方式有很多问题:
首先,占用资源,这种方式需要每个用户经过认证之后,都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。
其次,扩展性差: 客户端认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,在一些分布式的场景下会限制了负载均衡器的能力,会限制了应用的扩展能力。
第三,容易遭受攻击: 这种基于cookie来进行用户识别的认证方式, 很容易被截获,用户就会很容易受到跨站请求伪造的攻击。
基于Token 的鉴权方式
由于session 认证的诸多问题,因此出现了基于token 的鉴权方式,这种方式不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。
基于token 鉴权的工作流程如下:
首先,客户端通过用户名密码来请求对应的API接口
第二,服务器会验证用户的信息
第三,服务器通过验证后会发送token给客户端
第四,客户端存储token,并在每次请求时附送上这个token值
第五,服务端验证token值,并返回数据
这种方式的典型代表就是JWT(Json web token , 它是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519),该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
它的特点如下:
体积小(一串字符串)。因而传输速度快
传输方式多样。可以通过 HTTP 头部(推荐)/URL/POST 参数等方式传输
严谨的结构化。它自身(在 payload 中)就包含了所有与用户相关的验证消息,如用户可访问路由、访问有效期等信息,服务器无需再去连接数据库验证信息的有效性,并且 payload 支持应用定制
支持跨域验证,多应用于单点登录
JWT通常由三部分组成:
头信息(header)
消息体(payload)
签名(signature)
如下所示:
// Header { "alg": "HS256", "typ": "JWT" }
// Payload { // reserved claims "iss": "a.com", "exp": "1d", // public claims "http://a.com": true, // private claims "company": "A", "awesome": true }
// $Signature HS256(Base64(Header) + "." + Base64(Payload), secretKey)
// JWT JWT = Base64(Header) + "." + Base64(Payload) + "." + $Signature
其工作流程如下:
首先,客户端通过发送HTTP 请求把账号密码发送给服务短,通常使用的是POST请求, 服务器会校验账号与密码是否合法,如果一致,则根据密钥生成一个 token 并返回,客户端收到这个 token 并保存在本地。在这之后,需要访问一个受保护的路由或资源时,只要附加上 token(通常使用 Header 的 Authorization 属性)发送到服务器,服务器就会检查这个 token 是否有效,并做出响应。
服务端接收到 token 之后,会逆向构造过程,解码出 JWT 的三个部分,这一步可以得到 sign 的算法及 payload,结合服务端配置的 secretKey,可以再次进行 $Signature 的生成得到新的 $Signature,与原有的 $Signature 比对以验证 token 是否有效,完成用户身份的认证,验证通过才会使用 payload 的数据。
如何保证接口安全性
要想实现接口的安全性,我们可以做到以下几点:
首先,我们需要采用HTTPS 对传输过程中的数据进行加密,避免使用HTTP 这种明文传输的协议,防止数据直接暴露在公网中,在使用HTTPS的同时要保证时间安全可靠的加密方法和SSL 协议,目前主流的是TLS1.2 和最新的TLS1.3。同时要对证书进行校验,因为即使是HTTPS协议,证书也是能够被伪造的。
其次,对接口设计一般会加入 token、timestamp和sign 这些参数,不同的参数有自己不同的用途:
timestamp,即时间戳,它是客户端调用接口时传入的当前时间戳,时间戳的目的是用于防止DoS攻击。每次调用接口时接口都会判断服务器当前系统时间和接口中传的的timestamp的差值,如果这个差值超过某个设置的时间,例如设置的时间是3分钟,那么这个请求将被拦截掉,如果在设置的超时时间范围内,是不能阻止DoS攻击的。timestamp机制只能减轻DoS攻击的时间,缩短攻击时间。如果黑客修改了时间戳的值可通过sign签名机制来处理。
sign,即签名,通常用于参数签名,防止参数被非法篡改,最常见的是修改金额等重要敏感参数, sign的值一般是将所有非空参数按照升续排序然后+token+key+timestamp+nonce(随机数)拼接在一起,然后使用某种加密算法进行加密,这种方式的好处就是,当被劫持后,修改其中的参数值,然后再继续调用接口,虽然参数的值被修改了,但是因为攻击者并不清楚sign是如何计算出来的,所以即可是篡改参数的值,但没法修改sign的值,当服务器调用接口前会按照sign的规则重新计算出sign的值然后和接口传递的sign参数的值做比较,如果相等表示参数值没有被篡改,如果不等,表示参数被非法篡改了,则不会返回真实的响应信息。
此外,接口设计时候要实现幂等性操作,所谓的幂等性操作就是为了防止重复性运算,我们可以将生成的签名和key保存到redis 中,并且设置超时时间,过期自动删除,当有重复的值存在则不会处理,就可以防止重复提交,从而保证请求结果一致性。
其使用流程如下:
接口调用方(客户端)向接口提供方(服务器)申请接口调用账号,申请成功后,接口提供方会给接口调用方一个AppKey和一个APP Secret参数
调用方申请App Key 和 App Secret 在生成请求时,将参数拼接后进行加密,例如使用HMAC-SHA256 或MD5加密,然后将 App Key, 加密结果追加到请求上。sign=加密(appId + timestamp + key)
服务收到请求后,根据App Key识别出调用方,解密得到参数以及对时间进行对比,判断是否超时,然后从字典中查询到对应的App Secret,与请求参数拼接、加密,与请求中的签名进行对比,签名结果相同的为合法请求。
以上就是给API 接口设计的一些建议,仅供参考,在实际的应用中还可以追加一些公共的参数,例如Host、接口的版本等等参数去进行校验保证接口的安全性。
相关推荐
- 当 Linux 根分区 (/) 已满时如何释放空间?
-
根分区(/)是Linux文件系统的核心,包含操作系统核心文件、配置文件、日志文件、缓存和用户数据等。当根分区满载时,系统可能出现无法写入新文件、应用程序崩溃甚至无法启动的情况。常见原因包括:...
- 玩转 Linux 之:磁盘分区、挂载知多少?
-
今天来聊聊linux下磁盘分区、挂载的问题,篇幅所限,不会聊的太底层,纯当科普!!1、Linux分区简介1.1主分区vs扩展分区硬盘分区表中最多能存储四个分区,但我们实际使用时一般只分为两...
- Linux 文件搜索神器 find 实战详解,建议收藏
-
在Linux系统使用中,作为一个管理员,我希望能查找系统中所有的大小超过200M文件,查看近7天系统中哪些文件被修改过,找出所有子目录中的可执行文件,这些任务需求...
- Linux 操作系统磁盘操作(linux 磁盘命令)
-
一、文档介绍本文档描述Linux操作系统下多种场景下的磁盘操作情况。二、名词解释...
- Win10新版19603推送:一键清理磁盘空间、首次集成Linux文件管理器
-
继上周四的Build19592后,微软今晨面向快速通道的Insider会员推送Windows10新预览版,操作系统版本号Build19603。除了一些常规修复,本次更新还带了不少新功能,一起来了...
- Android 16允许Linux终端使用手机全部存储空间
-
IT之家4月20日消息,谷歌Pixel手机正朝着成为强大便携式计算设备的目标迈进。2025年3月的更新中,Linux终端应用的推出为这一转变奠定了重要基础。该应用允许兼容的安卓设备...
- Linux 系统管理大容量磁盘(2TB+)操作指南
-
对于容量超过2TB的磁盘,传统MBR分区表的32位寻址机制存在限制(最大支持2.2TB)。需采用GPT(GUIDPartitionTable)分区方案,其支持64位寻址,理论上限为9.4ZB(9....
- Linux 服务器上查看磁盘类型的方法
-
方法1:使用lsblk命令lsblk输出说明:TYPE列显示设备类型,如disk(物理磁盘)、part(分区)、rom(只读存储)等。...
- ESXI7虚机上的Ubuntu Linux 22.04 LVM空间扩容操作记录
-
本人在实际的使用中经常遇到Vmware上安装的Linux虚机的LVM扩容情况,最终实现lv的扩容,大多数情况因为虚机都是有备用或者可停机的情况,一般情况下通过添加一块物理盘再加入vg,然后扩容lv来实...
- 5.4K Star很容易!Windows读取Linux磁盘格式工具
-
[开源日记],分享10k+Star的优质开源项目...
- Linux 文件系统监控:用脚本自动化磁盘空间管理
-
在Linux系统中,文件系统监控是一项非常重要的任务,它可以帮助我们及时发现磁盘空间不足的问题,避免因磁盘满而导致的系统服务不可用。通过编写脚本自动化磁盘空间管理,我们可以更加高效地处理这一问题。下面...
- Linux磁盘管理LVM实战(linux实验磁盘管理)
-
LVM(逻辑卷管理器,LogicalVolumeManager)是一种在Linux系统中用于灵活管理磁盘空间的技术,通过将物理磁盘抽象为逻辑卷,实现动态调整存储容量、跨磁盘扩展等功能。本章节...
- Linux查看文件大小:`ls`和`du`为何结果不同?一文讲透原理!
-
Linux查看文件大小:ls和du为何结果不同?一文讲透原理!在Linux运维中,查看文件大小是日常高频操作。但你是否遇到过以下困惑?...
- 使用 df 命令检查服务器磁盘满了,但用 du 命令发现实际小于磁盘容量
-
在Linux系统中,管理员或开发者经常会遇到一个令人困惑的问题:使用...
- Linux磁盘爆满紧急救援指南:5步清理释放50GB+小白也能轻松搞定
-
“服务器卡死?网站崩溃?当Linux系统弹出‘Nospaceleft’的红色警报,别慌!本文手把手教你从‘删库到跑路’进阶为‘磁盘清理大师’,5个关键步骤+30条救命命令,快速释放磁盘空间,拯救你...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)