3

我尝试通过已建立的 SSL 连接发送一个 byte[] () (握手等已完成)。

结果: byte[] 被分成两个数据包(参见下面的调试):

  • 第一个数据包:只是应用程序数据的第一个字节(** 01 **)。
  • 第二个数据包:其余(fe db 01 00 ...)650 字节

有没有办法在一个数据包中提交所有应用程序数据字节?

流发送 651 字节:

**01** fe db 01 00 00 02 83 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 2e 30 22 20 65 6e 63 6f 64 69 6e 67 3d 22 75 73 2d 61 73 63 69 69 22 20 73 74 61 6e 64 61 6c 6f 6e 65 3d 22 6e 6f 22 3f 3e …

javax.net.debug 输出

Padded plaintext before ENCRYPTION:  len = 32
0000: **01** 06 03 06 46 7F 7F AE   D4 E8 30 5D B7 DB 3C 44  ....F.....0]..<D
0010: 02 08 C9 2A A1 0A 0A 0A   0A 0A 0A 0A 0A 0A 0A 0A  ...*............
1, WRITE: TLSv1 Application Data, length = 32
[Raw write]: length = 37
0000: 17 03 01 00 20 B3 4E EE   CE 5B 69 EC A5 4A 80 7F  .... .N..[i..J..
0010: D6 03 35 AF 6A 7B 85 17   B7 46 A2 31 B2 EF 7E D0  ..5.j....F.1....
0020: EA 1B 67 7E ED                                     ..g..
Padded plaintext before ENCRYPTION:  len = 672
0000: FE DB 01 00 00 02 83 3C   3F 78 6D 6C 20 76 65 72  .......<?xml ver
0010: 73 69 6F 6E 3D 22 31 2E   30 22 20 65 6E 63 6F 64  sion="1.0" encod
0020: 69 6E 67 3D 22 75 73 2D   61 73 63 69 69 22 20 73  ing="us-ascii" s
0030: 74 61 6E 64 61 6C 6F 6E   65 3D 22 6E 6F 22 3F 3E  tandalone="no"?>
[…]
4

3 回答 3

3

Sun 的 impl 评论:

默认情况下,我们通过在每个有效负载的第一条记录中发送一个字节的应用程序数据,并在后续记录中发送其余字节,来对抗 SSLv3/TLS1.0 中 CBC 模式密码套件的选择明文问题。请注意,这些问题已在 TLS 1.1 或更高版本中得到解决。

实验SSLEngine.wrap( largePlainText )表明它产生了 2 条 SSL 记录,第 1 条记录包含 1 字节的纯文本,第 2 条记录包含 15846 字节的纯文本。

接收器 API 可能会逐条处理记录,因此它将为第一次读取返回 1 个字节。

我们还可以在其他 SSL 实现中观察到这种行为,例如来自 Web 浏览器的 HTTPS 请求。

OpenSSL 插入空记录来抵御攻击。如果接收方是 Java SSL 套接字,则输入流不能为 read() 返回 0 字节,因此会跳过记录。其他接收器可能没有为 0 长度记录做好准备,并且可能会中断。

于 2012-11-23T19:21:40.147 回答
1

您所做的关于byte[]在另一端完全按照您编写的方式阅读的假设是典型的 TCP 错误。它实际上并不特定于 SSL/TLS,但也可能发生在 TCP 连接上。

在 TCP(和 SSL/TLS)中,不能保证读取器的缓冲区将填充与写入器缓冲区中的数据包完全相同的数据包长度。所有 TCP 保证都是按顺序交付的,因此您最终会获得所有数据,但您必须将其视为流。

这就是为什么使用 TCP 的协议依靠指示符和分隔符来告诉另一端何时停止读取某些消息。

例如,HTTP 1.1 使用空行来指示标头何时结束,并使用Content-Length标头告诉接收者期望的实体长度(或分块传输编码)。SMTP 还使用换行符和.在消息的末尾。

如果您正在设计自己的协议,则需要定义一种方式,让接收者知道您定义的有意义的数据单元何时被分隔。当您读取数据时,读取此类指示符并填充您的读取缓冲区,直到您获得您期望的字节数或直到您找到您定义的分隔符。

于 2012-11-23T13:42:55.137 回答
0

在看到此页面之前,我遇到了同样的问题: http ://bugs.java.com/bugdatabase/view_bug.do?bug_id=7157903

因此,我使用 -Djsse.enableCBCProtection=false 参数运行 JVM,现在数据没有被拆分。

最好的祝福

于 2015-01-14T11:40:14.843 回答