Android计算机网络学习总结

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)​​:

Kotlin 复制代码
// 初始化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代码示例​:

java 复制代码
// 生成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(推荐),与密文一起存储。
    • 计数器模式:对大型文件分块加密,使用递增计数器(需全局唯一)。
    java 复制代码
    // 生成随机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密钥对)​​:

java 复制代码
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. 迁移方案​:

    • 代码层替换

      java 复制代码
      // 废弃代码
      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. 代码级防护​:

    • 生物认证绑定

      java 复制代码
      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时,明确指定支持的协议版本,禁用老旧版本

Kotlin 复制代码
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倍以上,用户完全无感知。

相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习