主頁 >  其他 > java安全編碼指南之:Number操作

java安全編碼指南之:Number操作

2020-09-12 09:39:14 其他

文章目錄

  • 簡介
  • Number的范圍
  • 區分位運算和算數運算
  • 注意不要使用0作為除數
  • 兼容C++的無符號整數型別
  • NAN和INFINITY
  • 不要使用float或者double作為回圈的計數器
  • BigDecimal的構建
  • 型別轉換問題

簡介

java中可以被稱為Number的有byte,short,int,long,float,double和char,我們在使用這些Nubmer的程序中,需要注意些什么內容呢?一起來看看吧,

Number的范圍

每種Number型別都有它的范圍,我們看下java中Number型別的范圍:

考慮到我們最常用的int操作,雖然int的范圍夠大,但是如果我們在做一些int操作的時候還是可能超出int的范圍,

超出了int范圍會發送什么事情呢?看下面的例子:

    public void testIntegerOverflow(){
        System.out.println(Integer.MAX_VALUE+1000);
    }

運行結果:-2147482649,

很明顯Integer.MAX_VALUE+1000將會超出Integer的最大值范圍,但是我們沒有得到例外提醒,反而得到了一個錯誤的結果,

正確的操作是如果我們遇到了Overflow的問題,需要拋出例外:ArithmeticException,

怎么防止這種IntegerOverflow的問題呢?一般來講,我們有下面幾種方式,

  • 第一種方式:在做Integer操作之前,進行預判斷是否超出范圍:

舉個例子:

    static final int safeAdd(int left, int right) {
        if (right > 0 ? left > Integer.MAX_VALUE - right
                : left < Integer.MIN_VALUE - right) {
            throw new ArithmeticException("Integer overflow");
        }
        return left + right;
    }

上面的例子中,我們需要進行兩個整數相加操作,在相加之前,我們需要進行范圍的判斷,從而保證計算的安全性,

  • 第二種方式:使用Math的addExact和multiplyExact方法:

Math的addExact和multiplyExact方法已經提供了Overflow的判斷,我們看下addExact的實作:

    public static int addExact(int x, int y) {
        int r = x + y;
        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
        if (((x ^ r) & (y ^ r)) < 0) {
            throw new ArithmeticException("integer overflow");
        }
        return r;
    }

看下怎么使用:

    public int addUseMath(int a, int b){
        return Math.addExact(a,b);
    }
  • 第三種方式:向上轉型

既然超出了Integer的范圍,那么我們可以用范圍更大的long來存盤資料,

    public static long intRangeCheck(long value) {
        if ((value < Integer.MIN_VALUE) || (value > Integer.MAX_VALUE)) {
            throw new ArithmeticException("Integer overflow");
        }
        return value;
    }

    public int addUseUpcasting(int a, int b){
        return (int)intRangeCheck((long)a+(long)b);
    }

上面的例子中,我們將a+b轉換成了兩個long相加,從而保證不溢位范圍,

然后進行一次范圍比較,從而判斷相加之后的結果是否仍然在整數范圍內,

  • 第四種方式:使用BigInteger

我們可以使用BigInteger.valueOf(a)將int轉換成為BigInteger,再進行后續操作:

    public int useBigInteger(int a, int b){
        return BigInteger.valueOf(a).add(BigInteger.valueOf(b)).intValue();
    }

區分位運算和算數運算

我們通常會對Integer進行位運算或者算數運算,雖然可以進行兩種運算,但是最好不要將兩種運算同時進行,這樣會造成混淆,

比如下面的例子:

x += (x << 1) + 1;

上面的例子是想做什么呢?其實它是想將3x+1的值賦給x,

但是這樣寫出來讓人很難理解,所以我們需要避免這樣實作,

再看下面的一個例子:

    public void testBitwiseOperation(){
        int i = -10;
        System.out.println(i>>>2);
        System.out.println(i>>2);
        System.out.println(i/4);
    }

本來我們想做的是將i除以4,結果發現只有最后一個才是我們要的結果,

我們來解釋一下,第一個i>>>2是邏輯右移,將會把最左邊的填充成0,所以得出的結果是一個正值1073741821,

第二個i>>2是算數右移,最左邊的還是會填充成1,但是會向下取整,所以得出結果是-3.

直接使用i/4,我們是向上取整,所以得出結果是-2.

注意不要使用0作為除數

我們在使用變數作為除數的時候,一定要注意先判斷是否為0.

兼容C++的無符號整數型別

在java中只有16位的char表示的是無符號整數,而int實際上表示的是帶符號的整數,

而在C或者C++中是可以直接表示無符號的整數的,那么,如果我們有一個32位的無符號整數,該怎么用java來處理呢?

    public int readIntWrong(DataInputStream is) throws IOException {
        return is.readInt();
    }

看上面的例子,我們從Stream中讀取一個int值,如果是一個32位的無符號整數,那么讀出來int就變成了有符號的負整數,這和我們的期望是相符的,

考慮一下,long是64位的,我們是不是可以使用long來表示32位的無符號整數呢?

    public long readIntRight(DataInputStream is) throws IOException{
        return is.readInt() & 0xFFFFFFFFL; // Mask with 32 one-bits
    }

看上面的例子,我們回傳的是long,如果將32位的int轉換成為64位的long,會自動根據符號位進行補全,

所以這時候我們需要和0xFFFFFFFFL進行mask操作,將高32位重置為0.

NAN和INFINITY

在整型運算中,除數是不能為0的,否則直接運行例外,但是在浮點數運算中,引入了NAN和INFINITY的概念,我們來看一下Double和Float中的定義,

public static final double POSITIVE_INFINITY = 1.0 / 0.0;
public static final double NEGATIVE_INFINITY = -1.0 / 0.0;
public static final double NaN = 0.0d / 0.0;
public static final float POSITIVE_INFINITY = 1.0f / 0.0f;
public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;
public static final float NaN = 0.0f / 0.0f;

1除以0就是INFINITY,而0除以0就是NaN,

接下來,我們看一下NAN和INFINITY的比較:

public void compareInfinity(){
    System.out.println(Double.POSITIVE_INFINITY == Double.POSITIVE_INFINITY);
    }

運行結果是true,

    public void compareNaN(){
        System.out.println(Double.NaN == Double.NaN);
    }

運行結果是false,

可以看到NaN和NaN相比是false,

那么我們怎么比較NaN呢?

別急,Double提供了一個isNaN方法,我們可以這樣使用:

System.out.println(Double.isNaN(Double.NaN));

接下來我們看一個在代碼中經常會用到的一個Double決議:

    public void incorrectParse(String userInput){
        double val = 0;
        try {
            val = Double.valueOf(userInput);
        } catch (NumberFormatException e) {
        }
        //do something for val
    }

這段代碼有沒有問題?咋看下好像沒有問題,但是,如果我們的userInput是NaN,Infinity,或者-Infinity,Double.valueOf是可以決議得到結果的,

    public void testNaN(){
        System.out.println(Double.valueOf("NaN"));
        System.out.println(Double.valueOf("Infinity"));
        System.out.println(Double.valueOf("-Infinity"));
    }

運行輸出:

NaN
Infinity
-Infinity

所以,我們還需要額外去判斷NaN和Infinity:

public void correctParse(String userInput){
        double val = 0;
        try {
            val = Double.valueOf(userInput);
        } catch (NumberFormatException e) {
        }
        if (Double.isInfinite(val)){
            // Handle infinity error
        }

        if (Double.isNaN(val)) {
            // Handle NaN error
        }
        //do something for val
    }

不要使用float或者double作為回圈的計數器

考慮下面的代碼:

for (float x = 0.1f; x <= 1.0f; x += 0.1f) {
  System.out.println(x);
}

上面的代碼有什么問題呢?

我們都知道java中浮點數是不準確的,但是不一定有人知道為什么不準確,

這里給大家解釋一下,計算機中所有與的數都是以二進制存盤的,我們以0.6為例,

0.6轉成為二進制格式是乘2取整,0.6x2=1.2,取整剩余0.2,繼續上面的步驟0.2x2=0.4,0.4x2=0.8,0.8x2=1.6,取整剩余0.6,產生了一個回圈,

所以0.6的二進制格式是.1001 1001 1001 1001 1001 1001 1001 … 無限回圈下去,

所以,有些小數是無法用二進制精確的表示的,最終導致使用float或者double作為計數器是不準的,

BigDecimal的構建

為了解決float或者Double計算中精度缺失的問題,我們通常會使用BigDecimal,

那么在使用BigDecimal的時候,請注意一定不要從float構建BigDecimal,否則可能出現意想不到的問題,

    public void getFromFloat(){
        System.out.println(new BigDecimal(0.1));
    }

上面的代碼,我們得到的結果是:0.1000000000000000055511151231257827021181583404541015625,

這是因為二進制無法完美的展示所有的小數,

所以,我們需要從String來構建BigDecimal:

    public void getFromString(){
        System.out.println(new BigDecimal("0.1"));
    }

型別轉換問題

在java中各種型別的Number可以互相進行轉換:

比如:

  • short to byte or char
  • char to byte or short
  • int to byte, short, or char
  • long to byte, short, char, or int
  • float to byte, short, char, int, or long
  • double to byte, short, char, int, long, or float

或者反向:

  • byte to short, int, long, float, or double
  • short to int, long, float, or double
  • char to int, long, float, or double
  • int to long, float, or double
  • long to float or double
  • float to double

從大范圍的型別轉向小范圍的型別時,我們要考慮是否超出轉換型別范圍的情況:

    public void intToByte(int i){
        if ((i < Byte.MIN_VALUE) || (i > Byte.MAX_VALUE)) {
            throw new ArithmeticException("Value is out of range");
        }
        byte b = (byte) i;
    }

比如上面的例子中,我們將int轉換成為byte,那么在轉換之前,需要先判斷int是否超出了byte的范圍,

同時我們還需要考慮到精度的切換,看下面的例子:

    public void intToFloat(){
        System.out.println(subtraction(1111111111,1111111111));
    }

    public int subtraction(int i , float j){
        return i - (int)j;
    }

結果是多少呢?

答案不是0,而是-57,

為什么呢?

因為這里我們做了兩次轉換,第一次從1111111111轉換到float,float雖然有32位,但是只有23位是存放真正的數值的,1位是符號位,剩下的8位是指數位,

所以從1111111111轉換到float發送了精度丟失,

我們可以把subtraction方法修改一下,首先判斷float的范圍,如果超出了23bit的表示范圍,則說明發送了精度丟失,我們需要拋出例外:

    public int subtraction(int i , float j){
        System.out.println(j);
        if ((j > 0x007fffff) || (j < -0x800000)) {
            throw new ArithmeticException("Insufficient precision");
        }
        return i - (int)j;
    }

當然還有一種辦法,我們可以用精度更高的double來做轉換,double有52位來存放真正的資料,所以足夠了,

    public int subtractionWithDouble(int i , double j){
        System.out.println(j);
        return i - (int)j;
    }

本文的代碼:

learn-java-base-9-to-20/tree/master/security

本文已收錄于 http://www.flydean.com/java-security-code-line-number/

最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/13014.html

標籤:其他

上一篇:蘑菇街Java大牛純手寫肛出的(Spring AOP/IOC思維導圖原始碼筆記)

下一篇:fisco bcos 呼叫介面報錯WeBASE-Node-Manager user not logged in

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more