[Day16] 计算机网络八股文[2/2]

介绍一下 Websocket

webSocket 是为了实现服务器和客户端之间的全双工通信;在没有 WebSocket 之前 http 如果希望服务器推送消息只能通过服务端不断的轮询或者不断的发送长轮询;比如百度云的扫码登录就是通过长轮询实现的;轮询虽然能在使用层面上感觉是服务器推送但是实际上还是单向的; webSocket 则是通过 TCP 三次握手建立连接后将 http 请求进行升级为 webSocket 请求实现真正意义上的全双工,这样不会就能大大节省轮询带来的系统开销;常见的 websocket 运用场景就是在线聊天、协同编辑、视频弹幕;

websocket 也支持 https 加密从 ws 升级为 wss;认证也是同样携带 cookie 或者 jwt

java 原生 webSocket

@ServerEndpoint("/chat")
public class ChatServer {
    private static Set<Session> sessions = Collections.synchronizedSet(new HashSet<>());
    
    @OnOpen
    public void onOpen(Session session) {
        sessions.add(session);
    }
    
    @OnMessage
    public void onMessage(String message, Session session) {
        // 广播消息给所有客户端
        for (Session s : sessions) {
            s.getAsyncRemote().sendText(message);
        }
    }
    
    @OnClose
    public void onClose(Session session) {
        sessions.remove(session);
    }
}

SpringBoot 集成

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").withSockJS(); // 支持 SockJS 降级
    }
    
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic"); // 服务端推送前缀
        registry.setApplicationDestinationPrefixes("/app"); // 客户端请求前缀
    }
}


// 前端代码
let stompClient = Stomp.over(new SockJS('/ws'));
stompClient.connect({}, () => {
    stompClient.subscribe('/topic/messages', (message) => {
        console.log('Received: ' + message.body);
    });
    stompClient.send('/app/chat', {}, 'Hello WebSocket!');
});

SSE 与 WebSocket 有什么区别?

SSE: SSE 是一种单向的,由服务器单向客户端推送数据;在某些只需要客户端接收消息而不会主动推送的场景就很适用;比如:弹窗广告,实时新闻、股票行情等;还有 gpt 向用户推送数据流也是使用的 SSE,gpt 会先将一部分已经计算出来的数据主动推送给用户避免了全部计算完成后推送的这种方式下用户等待时间过长的问题;

所以 SSE 是单工的,只能服务器向客户端发送消息;webSocket 则是全双工的;这是两者最显著的区别;

在分布式场景下 WebSocket 如何做到广播推送消息?

在单体架构中一般采用一个 Map 保存所有连接用户信息,需要广播的时候只需要遍历所有用户拿到对应的流客户端进行推送即可;在分布式的场景下就必须把所有用户信息保存在一个所有分布式服务器都能功能访问的介质上,或者我们可以将广播的消息同步到各个服务器上;如果选择将广播发布到各个服务器上那么就很容易想到采用 redis 的发布订阅模式 pub/sub ,或者使用消息队列中的消息队列向每个节点服务器推送广播消息

WebSocket 的心跳检测机制

客户端会周期性地向服务器发送心跳检测;客户端发 ping 服务器响应 pong,证明连接双方都处于健康状态;如果心跳检测失败说明 webSokcet 连接不健康可以选主动释放来节省资源; websocket 的心跳检测周期一般是 20 到 60 秒,因为如果太频繁的话就和 http 通过轮询一样会造成很多的系统开销;并且 websocket 的心跳检测桢体积很小开销很小;

ping 的原理是什么?为什么不需要端口?

ping 命令是 ICMP 协议中的一个工具;通过向目标主机方式 ICMP 数据报判断主机之间的连通性;ICMP 是网络层的协议而端口概念是传输层的,所以 ping 不需要指定端口;

介绍一下 DNS

DNS 记录域名和 IP 映射的服务器;平常我们在访问网页是只会输入网址而不会记复杂的 ip 地址,DNS 就是记录了每个域名和 IP 映射的表;一般来说浏览器会先查看浏览器缓存是否有映射没有则会依次访问本地 DNS 缓存,然后根据域名逐级查询 DNS 服务器

什么是 DNS 污染?DNS 劫持?

DNS 污染和 DNS 劫持的主要原因就是因为 DNS 并不是 https 那样需要一个权威机构来认证 DNS 服务器的可靠性,而且 DNS 采用的是 UDP 请求,所以让查询的过程有可能会出现被窃听和穿改的问题;如果一个主机伪装成 DNS 服务器那么就可能将域名指向危险错误的 ip 地址;而 DNS 劫持则是黑客入侵了真正的 DNS 服务器然后继续数据的篡改导致所有查询都定向到危险的 IP

DNS 在某些场景下也是可以利用的;比如“墙”,就是通过将目标域名定位成为不可达并屏蔽某些 IP 地址实现的;

什么是正向代理和反向代理

正向和反向一般是相对客户端而言的;正常情况下是客户端向服务器发送请求,然后服务器响应;正向代理指的是在客户端向服务器发送请求的过程中,客户端将请求先发给正向代理服务器,并告知他目标服务器信息,然后由正向代理服务器向目标服务器请求并将结果返回给客户端,一般出现在客户端没有办法自己直接访问服务器的情况,比如学术研究过程中如果需要查看国外的文献,一般就会通过科学上网的方式,这就是典型的正向代理的案例;而反向代理则是通过在请求到达服务器之前经过反向代理服务器,反向代理服务器会验证请求是否合法然后根据情况将请求转发到内网中的某台服务器,常见的反向代理就使用 nginx,反向代理服务器可以对流量进行控制,还可以做负载均衡,对服务器端来说大大提高了安全性和性能;

什么是 CDN 为什么他可以做缓存

CDN 就通过部署分布式的 CDN 服务器进行数据备份;当用户需要向服务器索要静态资源的时候就会被就近的 CDN 服务器代理响应;这大大加速了响应速度,除了响应速度的加快外 CDN 还会采用压缩算法对资源进行压缩让传输效率更高;可以简单理解为在 JD 上面下单然后 JD 就会调度离用户最近的 JD 网点给用户配送商品

什么是跨域问题如何解决

跨域是因为浏览器的同源策略导致的;同源策略要求同一个网页中的资源必须来自同一个协议,同一个域名和同一个端口;只要有任意一部分不相同那么就会认为两个资源不同源就不能加载非同源的资源; 很明显跨域问题出现在前端,一般解决跨域问题前后端都可以实现;有以下几种常见的解决跨域的方法;

  • CORS;CORS 是在后端通过对前端的响应时设置请求头中的 Access-Control-Allow-origin 来指定允许跨域访问的域名或者通配符;
# CORS 
@CrossOrigin(origin = "*")
public class XXXController{}

JSONP;前端通过利用 <script> 标签动态加载的特性来加载资源绕过同源检测;

代理服务器;可以将所有前端的请求都先发往一个同源的代理服务器,然后由这个代理服务器对资源进行统一响应,这样就不会触发同源策略了;

什么是 DDoS 攻击?如何防止被攻击?

DDoS 攻击简单来说就是黑客伪装成正常用户发送大量请求来消耗服务器的资源和性能;最常见的 TCP 三次握手,黑客可能通过更改 ip 的方式让同一时间大量的不同 ip 连接请求打向服务器,然后可能拒绝响应或者建立连接后一直挂起造成服务器资源浪费; 避免 DDos 攻击可以从两方面出发,一方面就是提高服务器的性能,一方面就是识别出哪些是恶意攻击然后对恶意攻击的 ip 拉入黑名单;还可以对每个 ip 进行限流,或者通过外包的方式让第三方来保护服务器;DDoS 最麻烦的点就是无法区分哪些是正常用户请求哪些又是黑客攻击的请求,所以如何防御 DDos 的同时有不会影响正常用户的使用体验要权衡具体的情况分些决定;

什么是 CSRF 攻击?

CSRF 也成为 XSRF 是跨域请求伪造;这种攻击的原因是因为在浏览器中一个 tab 页可以读取到其他 tab 页中的 cookie;如果打开了一个攻击网页,那么攻击网页可能窃取 cookie 然后通过 cookie 伪造请求实现攻击; 解决方法:

  • 使用 Post 请求,提高攻击者持有 cookie 后的伪造难度;这种方法治标不治本;
  • 还可以设置 cookie 为 HttpOnly 限制这个 cookie 只能被一个域名访问;
  • 还有最常用的就是在服务器端分发 cookie 的时候带上一个 token,这个 token 不存在 cookie 中,验证时候必须 token 和 cookie 都合法才能通过;这样攻击者只获取到 cookie 是无法发动攻击的; SpringSecurity 就是采用这个方式防止 CSRF 攻击的

XSS 攻击?如何防止被攻击?

XSS 攻击就是黑客通过在网页的 HTML 中插入恶意代码前端,然后其他用户访问网页时就会无意间执行这些代码;比如在评论区中评论了一个弹出框的 js 代码;而且服务器没有进行过滤;那么其他正常用户访问评论区时就会触发这段 js 代码;这只是 XSS 的其中一种攻击方式 避免 XSS 的方法就是过滤所有用户提交的数据,避免代码注入;

MD 5 是加密算法吗?绝对安全吗?

MD 5 是通过散列算法将输入散列成固定长度的字符串;简单来说就是进行了一次 hash;这种方法并不是真正意义上的安全算法;我认为有以下两个原因

  • 如果我们通过穷举的方式来记录一张映射表,那么只要表够大我们就可以通过 hash 后的值查看 hash 前的值;比如很多人常用的密码是 123 经过 MD 5 加密后的值可以轻松计算比方说是 ABC,如果我们看到一个 MD 5 加密后的字符串是 ABC 那么就可以轻松查表得到原串为 123
  • 还有问题就是因为底层依赖的是 Hash 算法,而且结果串长度固定就意味着必定会存在 hash 碰撞,也就是两个不同的输入一个映射在了同一个值上,虽然 hash 冲突的发生概率不大但是也不是严格意义上的安全算法;

SHA-256 则是 MD 5 的升级版本,他的 hash 计算过程加入了更多了逻辑运算极大降低了碰撞的可能,碰撞可能极为为 0 所以我们认为 SHA-256 是安全的哈希算法

什么是水平越权?如何防止?

水平越权指的是一个用户操作到了不属于该用户的数据;这是因为后端在处理数据的时候盲目地相信前端传入的信息,而没有做判断资源 id 是否属于用户 id;比如之前某大厂的网盘出现了用户可以查看其他用户照片的问题,这就是典型的水平越权; 避免这种问题也很简单就是坚持不信任原则,涉及数据操作之前一定要从当前用户登录态中取出用户 id,对需要操作的资源要判断是否归属于当前用户; 对于一些十分敏感的数据还有可以采用 AK,SK 的方式,分发给用户,杜绝了其他用户的水平越权,相当于在资源层面添加了账号和密码;

什么是垂直越权,如何防止?

垂直越权是指用户执行了他本没有权限执行的操作;一般出现垂直越权说明系统的权限管理系统设计出现了严重漏洞,目前主流的权限校验框架都采用 RBAC 的设计模式,都不会出现垂直越权的情况;

加密&解密、加签&验签做的事情一样吗?

加解密的目的是将数据进行伪装保护,就是数据泄露或者被窃听,也不用担心别人获得原本的数据;加签是为了保证一个签名就算用明文传输,被窃听和泄露,也不用担心会被别人篡改; 常见的加解密比如 https 中采用非对称加密商议对称加密的密钥,然后通过密文传输,就算被窃听到数据也不用但是数据泄露; 常见的签名比如 JWT,服务器分发 JWT 并携带着签名信息;如果客户端或者黑客窃取后恶意修改了 JWT 那么服务端可以很快识别出 JWT 无效

什么是 SQL 注入攻击?如何防止

SQL 注入是值用户输入时恶意带上了 SQL 语句,服务器没有对用户的输入进行过滤和识别,直接用的输入作为了 SQL 语句的一部分,导致执行恶意 SQL 的目的;比如一个用户删除订单信息时应该传入自己的用户 id,但是攻击者在 id 后还写上了 OR True, 如果直接执行那么将会直接删除所有的数据; 防止 SQL 注意也有很多的方法:

  • 最常用的就是使用预编译语句;就是让 SQL 语句先编译要执行的语句,然后用占位符等待用户输入的数据,然后占位符会将用户输入的数据整体作为一个字符串传入;不会因为字符拼接语句带来 SQL 注入的问题
  • 使用 ORM 框架,比如 Mybaits 中就有 #{} ${} 来生成 SQL 语句;#{} 就是在执行前进行编译,${} 则是直接字符串拼接会有注入风险;
  • 控制权限的最小粒度避免出现水平越

什么是撞库、拖库和洗库?

撞库就是穷举用户可能的密码,可能是常识该用户的常用密码或者大家最常用的密码;这种攻击只需要规定在一个窗口期内的错误上限就可以了,比如我们的手机解锁密码重试上限,还有银行卡密码错五次后就会锁定用户;

拖库就是黑客入侵数据库然后对数据进行窃取;出现问题是严重的事故;我们要做好上层的网络安全外数据库层面也要做好数据的加密,比如用户密码等敏感信息不能存明文,要让就算拖库发生对用户和系统的损失降到最小;

洗库就是指黑客入侵数据库后对有价值的数据进行出售和变现,比如游戏中的等级、系统中无盘的价格;

#java##面试#
全部评论

相关推荐

评论
1
12
分享

创作者周榜

更多
牛客网
牛客企业服务