![bf919a7a94ff1a8ba2f98e80eb4682d7.gif](https://i-blog.csdnimg.cn/blog_migrate/78bbe6a02bcd709dddb744d14904a8de.gif)
学习JAVA的同学都知道,JAVA有8个基本数据类型。其中除char是无符号数据类型,其余数据类型均为有符号。在这些有符号的数据类型中,均存在数据类型溢出的问题。这个问题的危害其实非常的大,如果它应用于某些计算中,又没有对数据进行有效验证,那么有极大可能让攻击者利用并通过这个漏洞做出意想不到的结果。以下将详细讲解这个漏洞的成因和解决方案。
所谓有无符号是指首高位占位是否表示为正负号,在有符号的数据类型中,首高位为0时表示负数,首高位为1时表示正数。以byte型为例,byte占2字节,共16位。当byte的值为1时,其2进制表示为
![28ce79387919612f08fd58c27a6585f1.png](https://i-blog.csdnimg.cn/blog_migrate/cf394cec3bb968bb4cd6bab531e5900d.png)
当byte值为-1时,其正码表示为
![34d47a4b706b8566e71470372dc56dd6.png](https://i-blog.csdnimg.cn/blog_migrate/164c33da99188c776bb3b8f46f18fcbc.png)
但由于计算规则要求,需要进行反码运算。
所谓反码运算是指除首高位(即最左边第一位)符号位的值不变,其它各位原值为0的表为1原值为1的表为0。因此反码运算后结果为
![d5bf9cc7129677b2225547ad7ceddb1e.png](https://i-blog.csdnimg.cn/blog_migrate/aa1d053c8f44c5a617887d51fa7ecef9.png)
同时为了让计算机能够正确识别和计算,规定在反码的基础上进行补码。因此,-1的最终结果为
![cc43cf743f29e97bb06852a3f19391b5.png](https://i-blog.csdnimg.cn/blog_migrate/5949bb89ae6473a46f8dcdd134abd21c.png)
为避免出现-0这样的无效且冗余的表示,如:
![21a4c54f93f5299fdc620e0d54c1ea89.png](https://i-blog.csdnimg.cn/blog_migrate/68416e5cd61a339b5f7d39f8f865537d.png)
则规定,上述表示为负数最大值+1,即-128。我们不再深入讨论为什么要进行反码和补码运算,这将会在另外的篇章中进行,这里我们只需要记住负数需要反码和补码运算就好。接下来我们来看看数据是怎么溢出的
![2fe5c500fe0e961b5ae606dce144ba04.png](https://i-blog.csdnimg.cn/blog_migrate/144c99e0d58b40709368cda9d83b93d1.png)
上述代码初看并没有任何问题,我们申明了一个byte型的变量,其值为127,给它的值加上1后输出,但输出结果我们会发现是-128而非128。为什么会这样?我们先看看它原值127的2进制表示为
![540f2b01f75b9f418a43b6cf182c4839.png](https://i-blog.csdnimg.cn/blog_migrate/0b8ef375f7164f2cd58d12c25cd477b2.png)
那么,当我们给这个值+1后的结果又会是什么?在最右边的尾数上+1,我们发现它会不断进位,最终形成这样的结果
![b9b10f9c6a75ee0634e8cb5bf97ce9ec.png](https://i-blog.csdnimg.cn/blog_migrate/5bba067e8e8b238abdb22ce5d9bdb219.png)
前面我们讲过,在byte的2进制表示中,首高位为1则表示负数。因此,当这个变量+1后正好是我们前面讲到的-128
当上述代码改成b+2时,为什么又成了-127呢?同样,我们从127的原码中开始增加,127的2进制+2会形成如下结果
![0c86ad4791282155c605b3d7cea591bd.png](https://i-blog.csdnimg.cn/blog_migrate/15100c9c62a1cb28bc0594ac11abf4d1.png)
但是注意,此时的计算机会认为,这个结果已经是反码和补码后的结果。在写出计算时修正结果,进行同样的反码补码运算。注意:这里在“最后一位减掉再反码”和“全部反码后再补码“的数学计算上都是一样的
![cfe8ad7ac10d7c36a50afe9292b3efce.png](https://i-blog.csdnimg.cn/blog_migrate/4ec2ca424ab27d1c0083509d29924134.png)
因此,最后写出时计算机会认为它的真值表示为
![2de7fe7d4b0a80961d063e9f9dd085fb.png](https://i-blog.csdnimg.cn/blog_migrate/dbe844712f1e425899d45674bbc2cc89.png)
即为-127
我们知道,在JAVA中任何数字默认都表示为int型。如果b+1的结果不强制转为byte这个结果也会默认为int,那么它并不会出现类型溢出的问题。事实也正是如此,在JAVA中我们很少发现其它类型的溢出,而int的溢出漏洞却经常发现。
Int型溢出过程与byte溢出过程原因一致。为了避免这个漏洞的产生,通常我们采用以下几种方法验证参与运算的因子大小,并用更大的数据类型来保存结果。
例如:用户输入a和b两个数,验证a、b两数的范围不可大于int型最大值,但用长整形来接收
![a05e227da94f010dffaed1dabe68db05.png](https://i-blog.csdnimg.cn/blog_migrate/cdefc81f13ef50ee9886970ce2a325cd.png)
这种方式并不能从根本上解决问题,所以更好的建议是使用 java.util.BigInteger类 来解决。
![37b55051811bac9b4b3e69311b713768.png](https://i-blog.csdnimg.cn/blog_migrate/c0a7529d5091a1d8c95b7e23adaa9053.png)
![84e8be464c6a8acf44d9458ce0ce7612.png](https://i-blog.csdnimg.cn/blog_migrate/bdb8aa8ab6e408cf6fad19beeb30f019.png)
采编排:左 左