Android计算机网络学习总结

发布于:2025-05-24 ⋅ 阅读:(18) ⋅ 点赞:(0)
TCP vs UDP 核心区别​

题目​:TCP为什么称为可靠传输协议?UDP在哪些场景下比TCP更具优势?

得分要点​:

  • 可靠性机制

    • 三握四挥建立可靠连接
    • 确认应答(ACK)+ 超时重传
    • 滑动窗口流量控制
    • 拥塞控制(慢启动/AIMD)
  • UDP优势场景

    • 低延迟优先​:实时音视频(Zoom/RTC)、在线游戏(丢包影响<延迟影响)
    • 广播/多播​:DHCP服务发现、IPTV流媒体
    • 简单查询​:DNS请求(通常使用UDP)、SNMP监控

进阶考点​:QUIC协议如何结合UDP实现可靠传输?
解析方向​:QUIC在UDP之上实现自定义重传/拥塞控制,整合TLS 1.3减少握手次数,解决队头阻塞问题。


 三次握手进阶问题

题目​:如果第三次ACK丢失,TCP连接状态会如何变化?系统会有怎样的处理机制?

问题拆解​:

  1. 服务端状态变化:未收到ACK时维持SYN-RECEIVED状态
  2. 服务端重传:等待超时后重传SYN-ACK包​(重试次数由tcp_synack_retries内核参数控制)
  3. 客户端行为:已进入ESTABLISHED,直接发送数据会触发服务端RST复位
  4. 连接建立失败判定条件:服务端超过最大重试次数后关闭半连接

避坑指南​:需区分TCP实现细节(如Linux的SYN cookies机制可防止SYN洪水攻击,此时不会维持半连接状态)。


HTTPS加密流程

题目​:请描述从客户端发起HTTPS请求到完成加密通信的全流程,重点说明RSA和AES分别在哪个阶段使用。

标准化回答模板​:

  1. TCP连接建立​:完成三次握手
  2. TLS握手阶段
    • 客户端发送ClientHello(包含支持的加密套件、随机数)
    • 服务器回复ServerHello(选定套件)+ 证书(RSA公钥)+ ServerRandom
    • 客户端验证证书合法性,生成PreMasterSecret并用RSA公钥加密传输
    • 双方通过PRF生成MasterSecret,推导出AES对称会话密钥
  3. 加密数据传输​:应用层HTTP数据使用AES-GCM加密后传输
  4. 连接关闭​:发送close_notify警报终止加密信道

技术亮点​:强调前向保密(Forward Secrecy)的重要性。若使用ECDHE密钥交换,即使服务器私钥泄露,历史会话仍安全。


基础知识

以下为 ​加密算法分类与对比​ 的大厂面试真题深度解析,结合腾讯、阿里、字节等高频考点,覆盖对称加密、非对称加密、哈希算法的核心知识点:

一、HTTP状态码(面试必考)​

1. 核心分类与常见状态码
状态码范围 类别 常见状态码及场景 Android处理建议
1xx 信息响应 100 Continue(客户端应继续发送请求体) 通常由框架自动处理,无需业务层干预
2xx 成功响应 200 OK​(标准成功)
201 Created​(资源已创建,如POST成功)
204 No Content​(成功但无返回体,如DELETE请求)
检查响应体格式(如JSON解析是否兼容空响应)
3xx 重定向 301 Moved Permanently​(永久重定向)
302 Found​(临时重定向)
304 Not Modified​(缓存有效,结合If-Modified-Since)
处理重定向逻辑(如OkHttp默认自动跟进,可禁用:.followRedirects(false)
4xx 客户端错误 400 Bad Request​(请求格式错误)
401 Unauthorized​(未认证)
403 Forbidden​(无权限)
404 Not Found​(资源不存在)
弹窗提示用户(如401跳转登录页,404显示错误页)
5xx 服务端错误 500 Internal Server Error​(服务器内部错误)
502 Bad Gateway​(网关错误)
503 Service Unavailable​(服务不可用,如超载或维护中)
重试机制(指数退避)
降级策略(如展示缓存数据)
2. 面试高频问题

问题​:503和504状态码有什么区别?如何处理?
​:

  • 503(服务不可用)​​:服务器暂时过载或维护,客户端应稍后重试。常见于秒杀活动或流量高峰。
  • 504(网关超时)​​:服务器作为网关时,未及时从上游服务收到响应。可能因网络问题或上游服务故障。
  • 处理策略​:
    • 503:客户端启用退避重试(如首次1秒后重试,第二次3秒后)。
    • 504:检查网络连接,若正常则提示用户“服务响应超时”。

问题​:304状态码是如何工作的?
​:
服务器通过对比请求头中的If-Modified-Since(时间戳)或If-None-Match(ETag哈希)与资源最新版本,若未变化则返回304,客户端使用本地缓存。在Android中可通过Cache-ControlETag实现高效缓存,减少流量消耗。


二、QUIC协议:基于UDP的下一代HTTP/3

1. 核心特性与优势
特性 说明 对移动端的优势
基于UDP 绕过TCP协议栈,避免队头阻塞(Head-of-Line Blocking) 弱网环境下(如高丢包)性能提升显著
0-RTT连接 首次连接1-RTT,后续会话可0-RTT(类似TCP Fast Open但更彻底) 降低延迟,适合频繁短连接场景(如推送通知)
多路复用 每个流(Stream)独立传输,无需按序到达 页面加载速度更快(如同时传输HTML/CSS/JS)
前向纠错(FEC)​ 添加冗余数据包,部分丢包时无需重传 减少视频卡顿,提升实时音画质
连接迁移 客户端IP变化(如Wi-Fi切4G)时,连接保持可用 移动网络切换不断线
2. QUIC在Android中的应用

库与工具支持​:

  • OkHttp​:实验性支持(需启用okhttp-quic模块)。
  • Cronet​(Chromium网络库):Android官方推荐,支持QUIC和HTTP/3。

代码示例(Cronet)​​:

// 初始化Cronet引擎
val engine = CronetEngine.Builder(context)
    .enableQuic(true)
    .addQuicHint("example.com", 443, 443)
    .build()

// 发起QUIC请求
val request = engine.newUrlRequestBuilder(
    "https://example.com/api/data",
    MyUrlRequestCallback(),
    executor
).build()
request.start()

性能对比(QUIC vs TCP+TLS)​​:

  • 连接建立时间​:QUIC 0-RTT比TCP+TLS 1.3的1-RTT快约30%。
  • 弱网吞吐量​:在20%丢包率下,QUIC比HTTP/2快2倍以上。
3. 面试高频问题

问题​:QUIC为什么选择UDP而不是TCP?
​:

  • 避免TCP协议栈限制​:TCP由操作系统内核实现,修改困难;QUIC在用户空间实现,迭代更快。
  • 解决队头阻塞​:TCP要求数据包按序到达,一个丢包会阻塞整个流;QUIC的流相互独立,丢包只影响当前流。

问题​:QUIC如何保证安全性?
​:

  • 强制加密​:所有QUIC数据包默认使用TLS 1.3加密,无法明文传输。
  • 连接标识符​:连接ID与IP解耦,防止IP伪造攻击。

问题​:在Android中如何优化QUIC的弱网表现?
​:

  • 前向纠错(FEC)​​:开启FEC功能,容忍部分丢包。
  • 动态调整拥塞窗口​:根据网络类型(Wi-Fi/4G)自动选择算法(如BBR)。
  • 0-RTT会话恢复​:缓存会话凭证,网络切换时快速恢复连接。

三、真题场景:QUIC实战优化​

面试官​:你们在短视频加载中如何应用QUIC?具体提升了哪些指标?

​:
我们在视频预加载和首帧优化中引入了QUIC,核心策略有两点:

  1. 0-RTT连接复用​:用户打开App时,提前与CDN建立QUIC会话,后续请求跳过握手,首帧时间从500ms降到200ms。
  2. 多流并行传输​:视频元数据、分片数据、封面图通过不同QUIC流传输,即使某个流丢包,其他流不受影响,整体加载成功率从92%提升到98%。

数据验证​:

  • 弱网(30%丢包)​​:QUIC比HTTP/2的卡顿率降低60%。
  • 连接迁移测试​:Wi-Fi切4G时,QUIC视频续播成功率100%,TCP组为85%。

真题一:HTTPS为何采用混合加密?

问题​:HTTPS同时使用对称加密和非对称加密,为什么不直接用非对称加密传输所有数据?

答案拆解​:

  1. 性能差异​:

    • 对称加密(AES)​​:加密速度极快(如AES-256加密1GB数据仅需约0.5秒),适合大量数据传输。
    • 非对称加密(RSA)​​:加密速度慢(RSA-2048加密同样数据需约10分钟),仅适合小数据(如密钥交换)。
  2. 密钥管理难题​:

    • 若仅用非对称加密,每次传输需用公钥加密数据,但公钥可能被中间人替换(需依赖证书体系)。
    • 混合加密中,非对称加密仅用于传输对称密钥(如AES密钥),后续通信由对称加密完成,兼顾安全与效率。

Android代码示例​:

// 生成AES会话密钥(实际由TLS协议自动完成)
KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
aesKeyGen.init(256);
SecretKey aesKey = aesKeyGen.generateKey();

// 用RSA公钥加密AES密钥(模拟TLS握手过程)
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
rsaCipher.init(Cipher.ENCRYPT_MODE, serverPublicKey);
byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded());

陷阱规避​:

  • RSA填充模式​:必须使用OAEP(而非PKCS#1 v1.5),避免Bleichenbacher攻击。
  • 密钥长度​:RSA密钥需≥2048位,否则易被暴力破解。

真题二:为何推荐AES-GCM而非AES-CBC?

问题​:在Android文件加密中,为何GCM模式比CBC更安全?如何避免GCM的IV重复问题?

答案拆解​:

  1. GCM核心优势​:

    • AEAD模式​:同时提供加密和认证(Authenticated Encryption with Associated Data),无需额外计算HMAC。
    • 抗Padding Oracle攻击​:CBC需要填充(如PKCS#7),攻击者可利用填充错误获取明文信息。
    • 并行计算​:GCM基于CTR模式,支持多核CPU加速(比CBC快30%+)。
  2. IV管理方案​:

    • 随机生成IV​:每次加密生成12字节随机IV(推荐),与密文一起存储。
    • 计数器模式​:对大型文件分块加密,使用递增计数器(需全局唯一)。
    // 生成随机IV(Android最佳实践)
    SecureRandom random = new SecureRandom();
    byte[] iv = new byte[12];
    random.nextBytes(iv);
    GCMParameterSpec spec = new GCMParameterSpec(128, iv);
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);

延伸追问​:

  • GCM的认证标签(Authentication Tag)有何作用?​
    • 标签长度通常为128位,用于验证密文完整性和真实性,防止篡改。
  • 如何检测IV是否重复?​
    • 使用全局计数器或数据库记录已用IV(适用于低频操作),高并发场景推荐使用密码学安全的随机数生成器(如SecureRandom)。

真题三:RSA与ECC在移动端的应用对比

问题​:为何TLS 1.3强制使用ECDHE密钥交换,而不再支持RSA?这对Android应用有何影响?

答案拆解​:

  1. 前向安全性(Forward Secrecy)​​:

    • RSA密钥交换​:无前向安全性,若服务器私钥泄露,历史通信可被解密。
    • ECDHE(椭圆曲线DH)​​:每次会话生成临时密钥,即使私钥泄露,历史会话仍安全。
  2. 性能与资源占用​:

    • ECC密钥长度​:256位ECC ≈ 3072位RSA安全性,但计算速度快3倍,内存占用减少60%。
    • 握手速度​:ECDHE在移动端完成握手仅需100ms(RSA需300ms+)。

Android代码示例(生成ECC密钥对)​​:

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
    "EC", 
    "AndroidKeyStore"
);
keyPairGenerator.initialize(new KeyGenParameterSpec.Builder(
    "ecc_key",
    KeyProperties.PURPOSE_AGREE_KEY // 密钥协商用途
)
    .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
    .setDigests(KeyProperties.DIGEST_SHA256)
    .build());
KeyPair keyPair = keyPairGenerator.generateKeyPair();

陷阱规避​:

  • 曲线选择​:避免使用NIST未标准化的曲线(如secp192k1),推荐secp256r1或X25519。
  • Android版本兼容​:ECDHE在Android 4.3(API 18)及以上支持,需兼容旧版本时回退到RSA。

真题四:SHA-256替代MD5的必然性

问题​:为何Android P之后禁止MD5在TLS中使用?如何安全替换遗留系统中的MD5?

答案拆解​:

  1. 碰撞攻击风险​:

    • MD5​:2004年王小云团队攻破,可在1小时内构造碰撞(相同哈希的不同文件)。
    • SHA-256​:理论碰撞概率为1/(2^128),现有算力无法在合理时间内破解。
  2. 迁移方案​:

    • 代码层替换​:
      // 废弃代码
      MessageDigest md = MessageDigest.getInstance("MD5");
      
      // 修复代码
      MessageDigest md = MessageDigest.getInstance("SHA-256");
    • 数据迁移​:
      • 对已存储的MD5哈希值,要求用户重新输入密码并用SHA-256+盐值重新哈希。
      • 使用渐进式迁移策略:新用户用SHA-256,旧用户登录时强制升级。

延伸追问​:

  • HMAC-MD5是否安全?​
    • 若密钥保密,HMAC-MD5仍可用(但Android P+会警告),推荐升级到HMAC-SHA256。
  • 如何检测代码中的MD5使用?​
    • 使用Android Studio的Lint工具扫描MessageDigest.getInstance("MD5"),或SonarQube静态分析。

真题五:Android密钥存储的漏洞与防护​

问题​:如何防止Root后的设备提取Android Keystore中的密钥?

答案拆解​:

  1. 硬件级防护​:

    • TEE(可信执行环境)​​:密钥生成、存储、使用均在安全世界(Secure World)完成,普通进程无法访问。
    • StrongBox​:Android 9.0+支持独立安全芯片(如Google Titan M),密钥永不离开芯片。
  2. 代码级防护​:

    • 生物认证绑定​:
      KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
          "aes_key",
          KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
      )
          .setUserAuthenticationRequired(true)
          .setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG)
          .build();
    • 密钥有效期​:设置setUserAuthenticationValidityDurationSeconds(300),超时后需重新验证。

陷阱规避​:

  • 禁止密钥导出​:生成时设置setIsStrongBoxBacked(true)(若设备支持),并禁用setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
  • 防暴力破解​:使用setInvalidatedByBiometricEnrollment(true),生物信息变更后密钥自动失效。

面试话题回答

面试官​:嗨,我看你简历里提到熟悉网络通信原理,能简单聊聊TCP的三次握手吗?比如为什么需要三次而不是两次?

​:
啊,这个问题我之前学习的时候也纠结过。打个比方吧,就像两个人打电话确认彼此都能听见。假设客户端是A,服务器是B:

  • 第一次A打给B说“喂,能听到吗?”(SYN)
  • B听到后回“我能听到,你听得到我吗?”(SYN-ACK)
  • 这时候如果只有两次,A可能没听到B的回复就直接开始说话了,结果B根本没收到后续内容。所以A必须再回一句“嗯,我也能听到你”(ACK),这样双方才确定连接是双向通畅的。
    其实三次主要是为了防止历史连接的混乱。比如A之前发过一个旧的SYN请求,如果只用两次握手,B收到旧请求就直接建立连接,但A已经不认这个连接了,这时候B就会傻等…(笑)

面试官​:有意思的比喻。那实际开发中,Android应用怎么确保网络请求的安全性呢?比如用HTTP还是HTTPS?

​:
啊,这个问题我踩过坑!之前自己写Demo图方便用了HTTP,结果发现抓包工具随便看请求内容,吓得赶紧改HTTPS。现在如果是正式项目,肯定全走HTTPS的。不过具体实施的时候要注意几点:

  1. 证书校验​:比如用OkHttp的时候得设置CertificatePinner,防止中间人攻击。之前我测试时发现某些厂商手机会自己装证书,不配置的话HTTPS也可能被破解。
  2. 加密套件选择​:服务器得支持TLS 1.2以上,像我们学校的老系统还用TLS 1.0,用nscurl检查直接被判定不安全。
  3. 敏感数据防护​:就算用了HTTPS,密码之类的也不能明文传,得客户端加盐哈希再传输。对了,像Retrofit的@Body配合GSON会自动处理序列化,但要注意不要泄露日志里的请求体…

面试官​:说到Retrofit,如果让你设计一个图片加载模块,怎么平衡流畅度和流量消耗?

​:
这个场景我觉得得分层考虑。比如:

  • 缓存策略​:优先用内存缓存(LruCache),快速响应滚动。然后磁盘缓存存处理过的图片,像Glide会在本地存不同尺寸的副本。我之前尝试过用OkHttp的CacheInterceptor,但发现文件缓存需要自己控制过期时间。
  • 网络优化​:根据网络类型调整图片质量。比如Wi-Fi下加载原图,移动网络用WebP格式压缩。甚至可以在请求头里带Save-Data: on让CDN返回低分辨率图。
  • 懒加载和预加载​:RecyclerView滑动时不加载,停顿时再触发。像ViewPager可以预加载相邻页的图片,不过得注意内存压力。
    对了,之前我用Coil库发现它默认会根据ImageView大小下载合适尺寸的图,这个设计对流量节省挺有帮助的!

面试官​:如果现在有个需求:实现APP内的长连接消息推送,你会考虑哪些技术方案?

​:
长连接啊…这块我还没实际做过,但根据我查的资料,大概有几种思路:

  1. WebSocket​:比如用OkHttp的WebSocket支持,自己维护心跳包。优点是控制灵活,但得处理重连和保活,可能会比较耗电。
  2. Firebase Cloud Messaging(FCM)​​:如果是海外项目可以直接用,国内可能需要搭配厂商推送(小米、华为的SDK),但集成起来有点琐碎。
  3. MQTT协议​:听说适合物联网场景,轻量级。不过得自己搭服务器,像用EMQX这种开源方案。
    不管用哪种,我觉得都要考虑:
  • 保活机制​:Android系统后台会限制网络请求,可能需要用Foreground Service或者JobScheduler定期唤醒。
  • 消息可靠性​:比如离线消息存储,重发确认机制。对了,微信的推送好像走的是长连接+智能心跳,他们的技术博客提到过根据网络状态调整心跳间隔…

好的!以下是一个 ​模拟Android实习生面试对话模块​ ,用更自然的口语化表达还原真实面试场景,帮助你感受如何将知识点融入实际对话:


场景一:技术基础考察

面试官​:看你简历里提到了加密算法在Android中的应用,能简单说说HTTPS握手过程中对称加密和非对称加密是怎么配合的吗?

​:
嗯,好的。HTTPS握手其实是一个混合加密的过程。刚开始的时候,客户端和服务器会先用非对称加密(比如RSA或者ECC)来安全地交换一个对称加密的密钥。比如客户端生成一个随机的AES密钥,然后用服务器的公钥加密这个密钥传给服务器,服务器用自己的私钥解密拿到这个AES密钥。这样一来,后续的实际数据传输就可以用AES这种对称加密算法了,因为它速度更快,适合处理大量数据。整个过程有点像“先用保险箱寄钥匙,再用钥匙开锁运货”。

面试官追问​:为什么RSA只用来传密钥,而不是直接加密所有数据?
​:
因为RSA这类非对称加密算法计算量太大了。比如加密一段1MB的数据,RSA可能要花几秒钟,而AES可能只要几毫秒。所以为了性能和效率,实际数据用对称加密更合适。非对称加密就像快递员送钥匙,虽然安全但成本高,不能天天用;对称加密才是真正搬家的卡车,又快又能装。


场景二:实战场景分析

面试官​:假设你需要在Android里加密本地存储的用户登录密码,你会怎么设计?有没有遇到过什么坑?

​:
如果是加密密码的话,首先绝对不能用明文存,也不能直接用MD5这种简单的哈希。我之前在项目里用的是PBKDF2 + 盐值的方式。具体来说,用户输入密码后,我会生成一个随机盐值(比如16字节),然后用PBKDF2算法把密码和盐值混合起来,迭代个几万次(比如10万次),生成一个密钥。最后把这个盐值和哈希结果一起存到本地。这样即使数据库泄露,攻击者也没法直接用彩虹表破解。

不过实际开发的时候,我遇到过一个坑:一开始没处理好盐值的随机性,用了系统时间生成盐值,结果发现不同用户的盐值可能会重复。后来改用了SecureRandom类生成真随机数才解决这个问题。


场景三:开放性问题

面试官​:如果现在要你优化一个Android App的网络请求安全性,除了HTTPS,你还会考虑哪些点?

​:
除了HTTPS,我觉得还有几个方向可以优化。
第一是证书固定(SSL Pinning)​,比如用OkHttp的CertificatePinner把服务器证书的公钥哈希值写死在客户端,防止中间人攻击。
第二是双向认证(mTLS)​,比如让客户端也带证书,适合金融类App的高安全场景。
第三是敏感数据二次加密,比如即使走了HTTPS,用户的身份证号、银行卡号这类数据,可以用AES-GCM在业务层再加密一次。
最后还要注意降级攻击防护,比如在Network Security Config里禁用低版本的TLS,强制只用TLS 1.2+。


场景四:原理深挖

面试官​:你刚才提到AES-GCM比CBC更安全,能具体说说为什么吗?

​:
当然!CBC模式有一个问题叫“填充预言攻击”(Padding Oracle Attack)。简单来说,攻击者可以通过不断发送篡改过的密文,根据服务器的错误提示(比如返回“解密失败”还是“解密成功但数据无效”)来猜出明文内容。而GCM模式属于“认证加密”(AEAD),它在加密的同时会生成一个认证标签(Authentication Tag),解密时先验证这个标签,如果数据被篡改就直接拒绝,不会泄露任何信息。
另外,GCM不需要填充数据,所以天然避免了填充相关的漏洞,而且还能并行计算,性能更好,相当于既安全又省油。


场景五:学习能力考察

面试官​:如果现在要你学习一个陌生的加密算法(比如国密SM4),你会怎么快速上手?

​:
首先我会查官方文档或者RFC标准,了解它的设计原理、密钥长度、使用场景这些基本信息。
然后找开源库的Android实现,比如Bouncy Castle或者Conscrypt,看看它们的API文档和示例代码。
接着我会写个小Demo,比如用SM4加密一个字符串,对比加密前后的结果是否符合预期。
如果遇到问题,我会去GitHub上看Issues或者Stack Overflow,看看别人是怎么解决的。
最后,我可能会在本地写单元测试,模拟各种边界情况(比如空数据、超长数据),确保算法的稳定性和兼容性。​


场景一:DNS解析流程与优化

面试官​:用户在浏览器输入https://www.example.com,到最终建立连接,DNS解析经历了哪些步骤?你们在项目中如何优化这一过程?

​:
当用户输入网址后,系统会先检查本地缓存,比如浏览器和操作系统的DNS缓存,如果有记录就直接用。如果没找到,就会向本地DNS服务器(比如运营商提供的)发起查询。本地DNS会从根域名服务器开始,一步步找到负责.com的顶级域名服务器,再找到example.com的权威服务器,最终拿到IP地址。这个过程默认用UDP协议,因为速度快,适合小数据包。

在项目里,我们优化DNS解析主要是通过预解析缓存策略。比如在App启动时,提前解析核心域名(像API的域名),减少用户首次请求的等待时间。另外,我们用了OkHttp的DNS缓存功能,设置合理的TTL(比如5分钟),避免重复查询。对于弱网环境,还接入了HTTPDNS服务,绕过运营商DNS,直接通过HTTP请求权威服务器,这样既防劫持又提升了解析速度。

面试官追问​:如果遇到DNS劫持,你们是怎么检测的?
​:
我们会在关键业务场景(比如登录、支付)做双校验。首先,客户端解析域名拿到IP后,会通过另一个通道(比如用阿里云的HTTPDNS服务)再解析一次,对比两个IP是否一致。如果不一致,就触发告警,提示用户网络可能不安全。同时,在HTTPS握手时启用证书固定(Certificate Pinning),这样即使DNS被劫持,伪造的服务器证书也无法通过校验,连接会被直接终止。


场景二:TCP滑动窗口与性能优化​

面试官​:TCP的滑动窗口机制对移动端网络性能有什么影响?在Android开发中如何利用这一点优化请求速度?

​:
滑动窗口的核心是让发送方可以连续发多个数据包,而不用等每个包的确认,这样能充分利用带宽。比如窗口大小是3000字节,发送方可以一口气发3个1000字节的包,接收方确认后再继续发。这对移动端来说特别重要,因为网络波动大,减少等待时间能明显提升速度。

在Android里,我们通过OkHttp的配置来优化。比如调整connectionSpecs,启用TCP快速打开(Fast Open),减少握手次数。另外,在弱网环境下,我们动态调整超时时间——如果发现连续丢包,就缩小窗口大小,避免拥塞;网络恢复后再逐步扩大窗口。实际测试下来,下载大文件的平均速度提升了20%左右。

面试官追问​:如果滑动窗口的尺寸设置不合理,会导致什么问题?
​:
窗口太小的话,发送方总是要等确认,带宽利用率低,用户会觉得网速慢;窗口太大,一旦网络突然变差(比如进电梯),大量数据包堆积在中间节点,可能引发严重丢包,反而更慢。我们的做法是根据网络类型动态调整——Wi-Fi下窗口调大,4G适中,2G或弱信号时缩小,同时结合TCP的拥塞控制算法(比如BBR),尽量平衡速度和稳定性。


场景三:DNS劫持防护实战

面试官​:你们在App里是如何防止DNS劫持的?有没有遇到过什么棘手的案例?

​:
防DNS劫持我们用了三招:​HTTPS+证书固定HTTPDNS双解析校验。比如在支付环节,所有请求都强制走HTTPS,并且证书固定到几个特定的公钥哈希,这样即使DNS被黑,伪造的服务器也无法通过证书验证。同时接入了腾讯云的HTTPDNS服务,绕过本地DNS,直接从权威服务器获取IP,避免运营商劫持。

之前遇到过一个棘手问题:某个地区运营商的DNS会把无法解析的域名指向广告页面。我们当时的登录接口刚好用了第三方域名,被劫持后用户根本打不开登录页。临时方案是在客户端加入域名解析白名单,只有解析到指定IP才允许连接;长期方案是全面接入HTTPDNS,并且在后端做IP合法性校验,确保只有授权的服务器能响应。

面试官追问​:如果用户设备本身被黑了(比如hosts文件被篡改),你们怎么应对?
​:
这种情况我们会在App启动时做一次本地hosts文件扫描。比如检查/system/etc/hosts里是否有异常域名映射(像把淘宝域名指向陌生IP),如果发现就弹窗警告用户设备可能中毒。另外,关键业务接口不再依赖域名,改用IP直连+动态域名更新机制,后台定期下发最新的IP列表,即使hosts被改,也能通过IP直接连接正版服务器。


场景四:加密协议与Android安全

面试官​:为什么现在推荐用TLS 1.3?在Android里怎么保证低版本系统的兼容性?

​:
TLS 1.3主要两点优势:​更快更安全。它简化了握手过程,从原来的两次往返(2-RTT)变成一次(1-RTT),甚至零往返(0-RTT),连接速度提升明显。而且删除了不安全的加密算法(比如RC4、SHA-1),强制使用前向保密的密钥交换(比如ECDHE),即使私钥泄露,之前的通信记录也无法解密。

对于低版本Android(比如4.x),我们用的是OkHttp的兼容模式,通过ConnectionSpec.COMPATIBLE_TLS配置,支持TLS 1.2和1.3的协商。同时,在自定义SSLContext时,明确指定支持的协议版本,禁用老旧版本

val sslContext = SSLContext.getInstance("TLSv1.3")
sslContext.init(null, trustManagers, null)
val sslSocketFactory = sslContext.socketFactory

val client = OkHttpClient.Builder()
    .sslSocketFactory(sslSocketFactory, trustManager)
    .connectionSpecs(listOf(ConnectionSpec.MODERN_TLS)) // 强制TLS 1.3或1.2
    .build()

这样即使系统本身不支持TLS 1.3,OkHttp也会通过Conscrypt库提供兼容支持,确保高版本协议可用。


场景五:网络层安全与用户体验平衡

面试官​:在加强网络安全的过程中,你们是怎么平衡用户体验的?比如严格校验是否会影响请求速度?

​:
安全性和性能确实需要权衡。我们的原则是关键业务严格校验,非关键业务适度放宽。比如支付流程会做四重校验:DNS双解析、证书固定、报文签名、双向认证;而普通的图片加载只用HTTPS基础校验,避免过度消耗资源。

另外,我们会把部分校验逻辑后移到初始化阶段。比如App启动时预取证书、预加载DNS解析结果,这样用户实际操作时不会感觉到延迟。对于证书校验这种CPU密集型操作,还用了Native层优化(比如C++实现RSA验签),比纯Java快3倍以上,用户完全无感知。


网站公告

今日签到

点亮在社区的每一天
去签到