缓冲区溢出

最近发布了有效的Java第三版,我一直对确定此类Java开发书籍的更新感兴趣,该书籍的最新版本仅通过Java 6进行了介绍。 在此版本中,显然存在与Java 7 , Java 8和Java 9密切相关的全新项目,例如第7章(“ Lambda和流”)中的项目42至48,项目9(“建议尝试使用资源”最终尝试”)和第55条(“明智地退还可选方案”)。 我(非常有点)惊讶地意识到, Effective Java第三版中有一个新项目,并不是由Java的新版本专门驱动的,而是由独立于Java版本的软件开发领域的开发驱动的。 第85条(“ Java序列化的首选替代品”)是促使我撰写此介绍性文章的内容,内容涉及将Google的Protocol Buffers与Java结合使用。

Josh Bloch在“有效Java,第三版”的条款85中,以粗体强调了以下两个与Java序列化有关的断言:

  1. 避免序列化攻击的最佳方法是永远不要反序列化任何东西。
  2. 您没有理由在您编写的任何新系统中使用Java序列化。

在概述了Java反序列化的危险并做出了这些大胆的声明之后,Bloch建议Java开发人员使用他所谓的(跨平台的结构化数据表示形式)(以避免在讨论Java时与术语“序列化”相关的混淆)。 Bloch指出,该类别中的领先产品是JSON ( JavaScript对象表示法)和协议缓冲区( protobuf )。 我发现提到协议缓冲区很有趣,因为最近我一直在阅读和使用协议缓冲区。 在线全面介绍了JSON(甚至Java)的用法。 我觉得Java开发人员对协议缓冲区的了解不如对JSON的了解,因此,有必要在Java上使用协议缓冲区。

Google的协议缓冲区在其项目页面上被描述为“一种语言中立,平台中立的可扩展机制,用于序列化结构化数据。” 该页面添加了“思考XML,但是更小,更快,更简单”。 尽管协议缓冲区的优点之一是它们支持以可以被多种编程语言使用的方式表示数据,但本文的重点仅在于将协议缓冲区与Java结合使用。

有许多与协议缓冲区相关的有用在线资源,包括主项目页面, GitHub protobuf项目页面, proto3语言指南(也提供proto2语言指南),协议缓冲区基础:Java教程, Java生成的代码指南, Java API(Javadoc)文档,“协议缓冲区”发行页面和“ Maven存储库”页面。 这篇文章中的示例基于协议缓冲区3.5.1 。

协议缓冲区基础:Java教程概述了将协议缓冲区与Java一起使用的过程。 与使用Java相比,它涵盖了使用Java时要考虑的更多可能性和事情。 第一步是定义独立于语言的协议缓冲区格式。 这是在扩展名为.proto的文本文件中完成的。 对于我的示例,我已经在下一个代码清单中显示的文件album.proto描述了我的协议格式。

原始专辑

syntax = "proto3";option java_outer_classname = "AlbumProtos";
option java_package = "dustin.examples.protobuf";message Album
{string title = 1;repeated string artist = 2;int32 release_year = 3;repeated string song_title = 4;
}

尽管以上对协议格式的定义很简单,但其中有很多内容。 第一行明确指出我使用的是proto3,而不是未明确指定时使用的默认默认proto2 。 以option开头的两行仅在使用该协议格式生成Java代码时才有意义,它们指示最外层类的名称以及该最外层类的软件包,该类将被生成以供Java应用程序使用此协议格式使用。

“ message”关键字表示此结构(此处称为“专辑”)需要表示。 此构造中有四个字段,其中三个是string格式,一个是整数( int32 )。 在给定消息中,四个字段中的两个字段可以不止一次存在,因为它们用repeated保留字注释。 请注意,我创建此定义时没有考虑Java,除了两个option s,它们指定了根据此格式规范生成Java类的详细信息。

所述album.proto上述未示出的文件需要被“编译”到Java源类文件( AlbumProtos.javadustin.examples.protobuf包),将允许写入和读出协议缓冲器的二进制格式的对应于定义的协议格式。 使用适当的基于操作系统的存档文件中包含的protoc编译器可以完成Java源代码文件的生成。 就我而言,因为我正在Windows 10中运行此示例,所以我下载并解压缩了protoc-3.5.1-win32.zip以便访问该protoc工具。 下一张图片使用命令protoc --proto_path=src --java_out=dist\generated album.proto描述了我对album.proto运行的protoc

对于运行上面的,我有我的album.proto在文件src目录中指出--proto_path和我有一个创建(但空)目录下名为build\generated生成的Java源代码被放置在由按规定--java_out标志。

指定包中生成的类的Java源代码文件AlbumProtos.java有1000行以上,我不会在此处列出生成的类源代码,但是可以在GitHub上找到。 关于此生成的代码,需要注意的几件有趣的事情是缺少导入语句(完全合格的程序包名称代替了所有类引用)。 Java生成的代码指南中提供了有关由protoc生成的Java源代码的更多详细信息。 重要的是要注意,这个生成的类AlbumProtos仍然不受我自己的任何Java应用程序代码的影响,并且仅由文章前面显示的album.proto文本文件生成。

有了可用于AlbumProtos的生成的Java源代码,我现在将在其中生成该类的目录添加到IDE的源路径中,因为现在将其视为源代码文件。 我也可以将其编译为.class.jar用作库。 现在,在我的源路径中有了这个生成的Java源代码文件,我可以将其与自己的代码一起构建。

在继续本示例之前,我们需要一个简单的Java类来用Protocol Buffers表示。 为此,我将使用下一个代码清单(也在GitHub上提供)中定义的Album类。

相册

package dustin.examples.protobuf;import java.util.ArrayList;
import java.util.List;/*** Music album.*/
public class Album
{private final String title;private final List<String> artists;private final int releaseYear;private final List<String> songsTitles;private Album(final String newTitle, final List<String> newArtists,final int newYear, final List<String> newSongsTitles){title = newTitle;artists = newArtists;releaseYear = newYear;songsTitles = newSongsTitles;}public String getTitle(){return title;}public List<String> getArtists(){return artists;}public int getReleaseYear(){return releaseYear;}public List<String> getSongsTitles(){return songsTitles;}@Overridepublic String toString(){return "'" + title + "' (" + releaseYear + ") by " + artists + " features songs " + songsTitles;}/*** Builder class for instantiating an instance of* enclosing Album class.*/public static class Builder{private String title;private ArrayList<String> artists = new ArrayList<>();private int releaseYear;private ArrayList<String> songsTitles = new ArrayList<>();public Builder(final String newTitle, final int newReleaseYear){title = newTitle;releaseYear = newReleaseYear;}public Builder songTitle(final String newSongTitle){songsTitles.add(newSongTitle);return this;}public Builder songsTitles(final List<String> newSongsTitles){songsTitles.addAll(newSongsTitles);return this;}public Builder artist(final String newArtist){artists.add(newArtist);return this;}public Builder artists(final List<String> newArtists){artists.addAll(newArtists);return this;}public Album build(){return new Album(title, artists, releaseYear, songsTitles);}}
}

在定义了Java“数据”类(“ Album )并使用协议缓冲区生成的Java类(可以表示该专辑)的情况下( AlbumProtos.java ),我准备编写Java应用程序代码来“序列化”专辑信息,而无需使用Java序列化。 该应用程序(演示)代码位于GitHub上可用的AlbumDemo类中, 在本文中,我将着重AlbumDemo该类。

我们需要生成一个用于示例的Album实例,并通过下一个硬编码列表来完成。

生成Album样本实例

/*** Generates instance of Album to be used in demonstration.** @return Instance of Album to be used in demonstration.*/
public Album generateAlbum()
{return new Album.Builder("Songs from the Big Chair", 1985).artist("Tears For Fears").songTitle("Shout").songTitle("The Working Hour").songTitle("Everybody Wants to Rule the World").songTitle("Mothers Talk").songTitle("I Believe").songTitle("Broken").songTitle("Head Over Heels").songTitle("Listen").build();
}

Protocol Buffers生成的类AlbumProtos类包含一个嵌套的AlbumProtos.Album类,我将使用该类以二进制形式存储我的Album实例的内容。 下一个代码清单演示了如何完成此操作。

Album实例化AlbumProtos.Album

final Album album = instance.generateAlbum();
final AlbumProtos.Album albumMessage= AlbumProtos.Album.newBuilder().setTitle(album.getTitle()).addAllArtist(album.getArtists()).setReleaseYear(album.getReleaseYear()).addAllSongTitle(album.getSongsTitles()).build();

如前面的代码清单所示,“生成器”用于填充协议缓冲区生成的类的不可变实例。 参照该实例,我现在可以使用该实例上的toByteArray()方法轻松地以Protocol Buffers二进制格式写出该实例的内容,如下面的代码清单所示。

写作AlbumProtos.Album二进制形式

final byte[] binaryAlbum = albumMessage.toByteArray();

如下面的代码清单所示,可以完成将byte[]数组读回Album实例的操作。

AlbumProtos.Album二进制形式实例化Album

/*** Generates an instance of Album based on the provided* bytes array.** @param binaryAlbum Bytes array that should represent an*    AlbumProtos.Album based on Google Protocol Buffers*    binary format.* @return Instance of Album based on the provided binary form*    of an Album; may be {@code null} if an error is encountered*    while trying to process the provided binary data.*/
public Album instantiateAlbumFromBinary(final byte[] binaryAlbum)
{Album album = null;try{final AlbumProtos.Album copiedAlbumProtos = AlbumProtos.Album.parseFrom(binaryAlbum);final List<String> copiedArtists = copiedAlbumProtos.getArtistList();final List<String> copiedSongsTitles = copiedAlbumProtos.getSongTitleList();album = new Album.Builder(copiedAlbumProtos.getTitle(), copiedAlbumProtos.getReleaseYear()).artists(copiedArtists).songsTitles(copiedSongsTitles).build();}catch (InvalidProtocolBufferException ipbe){out.println("ERROR: Unable to instantiate AlbumProtos.Album instance from provided binary data - "+ ipbe);}return album;
}

如最后一个代码清单所示,在调用生成的类中定义的static方法parseFrom(byte[])过程中,可能引发检查异常InvalidProtocolBufferException 。 获得生成的类的“反序列化”实例本质上是一行,其余几行从生成的类的实例中获取数据,并将该数据设置在原始Album类的实例中。

演示类包括两行,这些行打印出原始Album实例的内容,以及最终从二进制表示形式检索到的实例。 这两行包括对两个实例的System.identityHashCode()调用,以证明即使内容匹配,它们也不是同一实例。 当使用前面显示的硬编码的Album实例详细信息执行此代码时,输​​出如下所示:

BEFORE Album (1323165413): 'Songs from the Big Chair' (1985) by [Tears For Fears] features songs [Shout, The Working Hour, Everybody Wants to Rule the World, Mothers Talk, I Believe, Broken, Head Over Heels, Listen]AFTER Album (1880587981): 'Songs from the Big Chair' (1985) by [Tears For Fears] features songs [Shout, The Working Hour, Everybody Wants to Rule the World, Mothers Talk, I Believe, Broken, Head Over Heels, Listen]

从此输出中,我们看到两个实例中的相关字段相同,并且两个实例确实是唯一的。 与使用Java的实现序列化接口的“近乎自动”序列化机制相比,这需要付出更多的努力,但是与这种方法相关联的重要优势可以证明成本合理。 Josh Bloch在有效的Java第三版中讨论了Java默认机制中与反序列化相关的安全漏洞,并断言“没有理由在编写的任何新系统中使用Java序列化。

翻译自: https://www.javacodegeeks.com/2018/01/using-googles-protocol-buffers-java.html

缓冲区溢出

缓冲区溢出_在Java中使用Google的协议缓冲区相关推荐

  1. java使用缓冲区读取文件_在Java中使用Google的协议缓冲区

    java使用缓冲区读取文件 最近发布了 有效的Java第三版 ,我一直对确定此类Java开发书籍的更新感兴趣,该书籍的最新版本仅通过Java 6进行了介绍 . 在此版本中,显然存在与Java 7 , ...

  2. 在Java中使用Google的协议缓冲区

    最近发布了 有效的Java第三版 ,我一直对确定此类Java开发书籍的更新感兴趣,该书籍的最新版本仅通过Java 6进行了介绍 . 在此版本中,显然有与Java 7 , Java 8和Java 9密切 ...

  3. python缓冲区_如何在Python中使用Google的协议缓冲区

    python缓冲区 When people who speak different languages get together and talk, they try to use a languag ...

  4. 缓冲区溢出_了解Java缓冲池

    缓冲区溢出 了解Java缓冲池 缓冲池空间位于垃圾收集器管理的内存之外. 这是分配本地堆外内存的一种方法. 使用缓冲池有什么好处? 为了回答这个问题,让我们首先了解什么是字节缓冲区. 字节缓冲区 非直 ...

  5. 谷歌去水印java实现_在Java中实现Google的“您的意思是”功能

    谷歌去水印java实现 介绍 搜索引擎用户经常因各种原因而拼写错误的搜索词,包括键盘问题(键不起作用),陌生的国际名称(例如Sigmund Freud),意外更改一个字母(Sinpsons)或添加一个 ...

  6. Java中的Google协议缓冲区

    总览 协议缓冲区是一种用于结构化数据的开源编码机制. 它是由Google开发的,旨在实现语言/平台中立且可扩展. 在本文中,我的目的是介绍Java平台上下文中协议缓冲区的基本用法. Protobuff ...

  7. java 缓冲区溢出_缓冲区溢出详解

    1 缓冲区溢出原理 缓冲区是一块连续的计算机内存区域,可保存相同数据类型的多个实例.缓冲区可以是堆栈(自动变量).堆(动态内存)和静态数据区(全局或静态).在C/C++语言中,通常使用字符数组和mal ...

  8. 缓冲区溢出攻击-C语言中的危险函数

    1.缓冲区溢出攻击 缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,溢出的数据覆盖在合法数据上.理想的情况是:程序会检查数据长度,而且并不允许输入超过缓冲区长度的字符.但是绝大多 ...

  9. 缓冲区溢出漏洞攻击演示实验(CProxy 6.2缓冲区溢出漏洞)

    实验内容: 分析缓冲区溢出漏洞,利用CCProxy 6.2的这个缓冲区溢出漏洞,利用ping命令向其发送一个长的字符串,溢出局部变量,覆盖RET的位置,从而实现程序跳转到自己想要让其执行的程序上去. ...

最新文章

  1. 【转载】Java异常控制机制和异常处理原则
  2. JAVA SE学习day_02:StringBuilder、正则表达式、Object
  3. 项目中涉及到的BAPI
  4. 《设计师要懂心理学》-第四章-人如何思考
  5. 永大服务器进去显示字母,永大电梯服务器使用说明
  6. WEBGL学习【四】模型视图矩阵
  7. 信息系统项目管理基础(1)
  8. OPPO Find X5/Pro搭载一体化流线设计,采用双芯片战略
  9. python画柱状图-python plotly画柱状图代码实例
  10. Probably at least one of the constraints in the following list is one you don't want.
  11. 腾讯地图api php经纬度转换地址,腾讯地图经纬度转换为百度地图经纬度PHP类
  12. OSChina 周三乱弹 —— 生活要懂得苦中作乐
  13. python二分法求函数零点_在SciPy/NumPy中求复函数的零点
  14. python 服务器和客户端 学习http请求和响应报文头
  15. npm ERR network Invalid response body while trying to fetch
  16. 全国哀悼日,网页变黑白
  17. node.js之async的使用(series,whilst)
  18. 如何禁止电脑随便修改IP?
  19. memcache数据组织
  20. 解决Oracle服务端1521端口无法telnet,服务名未开启监听问题

热门文章

  1. Android混淆代码
  2. 使用浏览器访问 Linux 终端的方法
  3. 解决程序与mysql的乱码问题
  4. python 目录遍历 目录文件列表 介绍
  5. xhr XMLHttpRequest 简介
  6. linux c 指针 内存 泄漏几种情况
  7. linux shell find命令 查找多种文件后缀
  8. python3 paramiko实现ssh客户端
  9. golang 下划线
  10. windows平台下 c++获取 系统版本 网卡 内存 CPU 硬盘 显卡信息