張鵬偉, 李建文
(陜西科技大學(xué) 電氣與信息工程學(xué)院, 陜西 西安 710021)
數(shù)據(jù)庫系統(tǒng)的安全問題是數(shù)據(jù)庫開發(fā)中重要考核指標(biāo)之一,但目前在我國由于字符編碼的混用,數(shù)據(jù)庫系統(tǒng)普遍存在著安全隱患.數(shù)據(jù)庫系統(tǒng)開發(fā)的主要任務(wù)是對(duì)文本字符進(jìn)行輸入、檢索、輸出,整個(gè)過程都離不開處理字符串的問題[1].隨著信息全球化的發(fā)展,現(xiàn)在的字符串已經(jīng)進(jìn)入多種字符編碼混用的時(shí)代[2-5].事實(shí)上,現(xiàn)在的大部分軟件開發(fā)工具都提供字符編碼的選擇功能,但由于人們對(duì)于字符編碼知識(shí)的缺失而忽視了字符編碼的正確選擇,以致于造成了實(shí)際應(yīng)用過程中的安全隱患.
圖1是Windows XP “記事本”中“另存為”時(shí)可選擇字符編碼的界面,里面出現(xiàn)了3種字符編碼,即ANSI、Unicode、UTF-8等,事實(shí)上還有ASCII、ISO8859等.我們只有搞清楚了它們之間的理論關(guān)系,才能開發(fā)出可靠的數(shù)據(jù)庫系統(tǒng).
圖1 Windows XP “記事本”中“另存為”選擇字符編碼
ANSI (American National Standards Institute)編碼就是將原來的ASCII字符擴(kuò)充為256個(gè),如圖2所示.后面的128個(gè)(0x80-0xFF)由其他國家用來構(gòu)造本國文字編碼.其中簡(jiǎn)體漢字、中文BIG5、日文漢字、韓文都特別多,需要2個(gè)ANSI字符才能拼成一個(gè)字符.
圖2 ASCII與ANSI字符集關(guān)系
Oracle數(shù)據(jù)庫的默認(rèn)編碼方式為ISO8859-1[6],即ASCII.ISO8859基本特點(diǎn)是:(1)與 ASCII 兼容;(2)碼位0x80-0x9F (或 128-159),保留給擴(kuò)充定義的 32 個(gè)控制碼,稱為 C1控制碼 (0-31 稱為C0控制碼);(3)每個(gè)字符集定義至多 95 個(gè)字符,其碼位都在 0xA1-0xFF(或 161-255).我國GB2312-80規(guī)定一個(gè)漢字由兩個(gè)擴(kuò)充ASCII碼0x80-0x9F拼成,所以漢字最多94*94個(gè),僅適用于簡(jiǎn)體漢字.
這樣雖然解決了各國文字使用計(jì)算機(jī)的問題,但隨著信息全球化的發(fā)展,人們又需要在同一臺(tái)計(jì)算機(jī)、同一個(gè)操作系統(tǒng)、同一套軟件內(nèi)容等中同時(shí)使用很多國家的文字.這便需要將全世界所有的字符進(jìn)行統(tǒng)一編碼,這就是Unicode.
通常所說的Unicode是UTF-16編碼[2,3].Unicode工作開始于1991年.UTF-16字符字節(jié)數(shù)統(tǒng)一為2字節(jié),16位,字符編碼范圍0-65535.其中,日文編碼0x3400-0x4DC0;中文漢字編碼0x4E00-0x9FC0,不分簡(jiǎn)體與繁體;韓文編碼0x3AC00-0x3D7C0.在原來的ANSI中,常用漢字以拼音為序,但在UTF-16中所有漢字以偏旁部首為序.
通常情況下,編碼中的Unicode是指UTF-16,見圖1.Unicode big endian是將Unicode的2個(gè)字節(jié)進(jìn)行了位置交換,仍然是UTF-16.由于UTF-16編碼中所有字符都是2個(gè)字節(jié),使得UTF-16編碼在存貯和字符檢索時(shí)很方便.但UTF-16編碼也有缺點(diǎn),主要是關(guān)于英文字符的編碼與ASCII不一致.在UTF-16中英文字符是2個(gè)字節(jié),在ASCII中英文字符是1個(gè)字節(jié),盡管順序完全一樣,在UTF-16中英文字符的高8位總為0.因此,UTF-16中在網(wǎng)絡(luò)上傳輸英文字符效率比ASCII低.事實(shí)上不僅僅是傳送英文字符文本,而且HTML中全部使用英文字符做傳輸指令的,即使傳送的全部是漢字文本,但仍然少不了HTML語言指令.在這樣的背景下,就誕生了UTF-8.
UTF-8是一種不定長(zhǎng)的字符編碼,可以看做是UTF-16的變種.UTF-8來源于UTF-16,但改變了UTF-16中所有字符字節(jié)數(shù)都是2的特征.UTF-8與UTF-16字符數(shù)一樣多,而且順序都一樣,UTF-8中分為1、2和3字節(jié)字符.UTF-16中字符編碼是連續(xù)的,由0到65535,按照16進(jìn)制就是0到FFFF.而UTF-8中字符編碼整體不連續(xù),但分段連續(xù),UTF-8的分段與UTF-16對(duì)應(yīng)關(guān)系如表1所示.
表1 UTF-8的分段與UTF-16對(duì)應(yīng)關(guān)系(16進(jìn)制)
事實(shí)上,3種字符編碼各有優(yōu)缺點(diǎn),現(xiàn)在都常用.其中ANSI仍然用于數(shù)據(jù)庫中,UTF-16是Unicode的標(biāo)準(zhǔn),OFFICE Word內(nèi)部完全使用UTF-16,UTF-8主要用于網(wǎng)頁傳送.
Windows操作系統(tǒng)為人們使用這3種字符編碼創(chuàng)造了良好的環(huán)境,以致于人們沒有感覺到字符編碼已經(jīng)發(fā)生了重大變化.這是由于平常我們對(duì)字符串進(jìn)行操作時(shí),Windows為我們進(jìn)行了自動(dòng)的轉(zhuǎn)換服務(wù),特別是進(jìn)行字符串的“COPY”過程.但是,我們必須知道以下3點(diǎn):
(1)UTF-16與UTF-8字符串進(jìn)行轉(zhuǎn)換時(shí)可以完全轉(zhuǎn)換,僅僅可以出現(xiàn)存貯空間上的差異,因?yàn)閁TF-16的字符一律2字節(jié),而UTF-8中英文字符占1個(gè)字節(jié),一個(gè)漢字占用3個(gè)字節(jié).
(2)ANSI字符轉(zhuǎn)換為Unicode字符時(shí)可以完全轉(zhuǎn)換,因?yàn)閷?duì)于每個(gè)指定的國家而言ANSI字符集僅僅是Unicode字符集的子集,可以向上映射但不能建立一一對(duì)應(yīng)映射.
(3)Unicode字符轉(zhuǎn)換為ANSI字符往往是無法進(jìn)行的,因?yàn)閷?duì)于每個(gè)指定的國家而言ANSI字符集簡(jiǎn)直太小了.
數(shù)據(jù)庫系統(tǒng)一般由用戶界面和后臺(tái)操作兩大部分組成,見圖3.用戶界面屬于前臺(tái),主要照顧到方便、美觀,往往與流行的編程工具和網(wǎng)絡(luò)環(huán)境關(guān)系極為密貼;數(shù)據(jù)庫屬于后臺(tái),主要照顧到可靠性和對(duì)于歷史數(shù)據(jù)的兼容性.往往數(shù)據(jù)庫系統(tǒng)的前臺(tái)和后臺(tái)所使用的字符編碼可能不一致.
用戶操作主要分為兩種,即數(shù)據(jù)錄入和數(shù)據(jù)查詢.數(shù)據(jù)錄入過程主要由用戶界面的數(shù)據(jù)錄入模塊實(shí)現(xiàn),具體的操作可能是鍵盤輸入,或者由其它文字塊拷貝實(shí)現(xiàn).數(shù)據(jù)錄入后經(jīng)保存后寫入后臺(tái)數(shù)據(jù)庫,這時(shí)如果前臺(tái)和后臺(tái)編碼不一致就必須經(jīng)過“前臺(tái)=>后臺(tái)編碼轉(zhuǎn)換”.這個(gè)轉(zhuǎn)換過程由操作系統(tǒng)自動(dòng)完成,操作者感覺不到.
數(shù)據(jù)查詢就是讀取數(shù)據(jù)庫中的數(shù)據(jù),并顯示在用戶界面中.相對(duì)于數(shù)據(jù)錄入來說,數(shù)據(jù)查詢更為頻繁,也可以說,數(shù)據(jù)錄入的目的就是為了數(shù)據(jù)查詢.如果前臺(tái)和后臺(tái)編碼不一致,在讀取數(shù)據(jù)庫數(shù)據(jù)后,就必須經(jīng)過“后臺(tái)=>前臺(tái)編碼轉(zhuǎn)換”[7].這個(gè)轉(zhuǎn)換過程也由操作系統(tǒng)自動(dòng)完成,一般情況下操作者感覺不到,除非經(jīng)過特殊的構(gòu)思才能發(fā)現(xiàn)問題.
圖3 數(shù)據(jù)庫前臺(tái)后臺(tái)編碼轉(zhuǎn)換示意圖
在字符錄入過程,由于使用了先進(jìn)的UTF-8,不會(huì)丟失任何字符.再寫入后臺(tái)時(shí),由于兩個(gè)字符編碼不一致會(huì)導(dǎo)致Unicode字符丟失.在查詢時(shí)又要發(fā)生一次字符編碼轉(zhuǎn)換,但這時(shí)是ANSI轉(zhuǎn)為Unicode,也不會(huì)發(fā)生字符丟失.在顯示字符時(shí)才發(fā)現(xiàn)字符丟失,但不是發(fā)生在顯示過程,而是發(fā)生在保存數(shù)據(jù)的過程.
如圖4、圖5所示,為基于J2EE的油田物資管理信息系統(tǒng)開發(fā)過程中出現(xiàn)的中文亂碼和數(shù)據(jù)丟失問題.在圖4中,由另一個(gè)包涵全部Unicode字符的文件中復(fù)制了一些日文漢字、日文符號(hào)和韓文,粘貼到鍵盤輸入框內(nèi),可以看到這些日文漢字、日文符號(hào)和韓文都可以出現(xiàn).但經(jīng)過“保存”后再查詢時(shí)便出現(xiàn)如圖5的情況,日文漢字、日文符號(hào)和韓文全部變成“???????”,這就是數(shù)據(jù)丟失現(xiàn)象.
圖4 數(shù)據(jù)錄入界面
圖5 數(shù)據(jù)查詢界面
根據(jù)字符編碼理論,這屬于典型的系統(tǒng)表現(xiàn)層、應(yīng)用層和數(shù)據(jù)層編碼不一致造成的結(jié)果.經(jīng)過仔細(xì)核對(duì)數(shù)據(jù)庫編碼方式,該系統(tǒng)使用了Oracle數(shù)據(jù)庫,編碼方式采用默認(rèn)的ISO8859-1編碼方式.系統(tǒng)應(yīng)用層開發(fā)采用J2EE技術(shù)框架,字符編碼選擇了UTF-8.而客戶端瀏覽器采用中文操作系統(tǒng)默認(rèn)的gb2312字符集.J2EE程序在編寫、編譯、輸入、輸出過程中采用的字符編碼不一致,導(dǎo)致了中文亂碼的產(chǎn)生或系統(tǒng)數(shù)據(jù)的丟失[8,9].ISO8859-1中僅能容納的文字和符號(hào)最多8 000多個(gè).Unicode中有全部的漢字、日文漢字、韓文和符號(hào),共六萬多個(gè).數(shù)據(jù)丟失發(fā)生在“保存”過程,絕大部分Unicode字符在轉(zhuǎn)換為ISO8859-1時(shí)都會(huì)被丟失,但常用的簡(jiǎn)體漢字卻不會(huì)丟失.這正是為什么丟失字符的現(xiàn)象反而不容易被人們發(fā)現(xiàn)的原因.
解決上述數(shù)據(jù)丟失和中文亂碼問題的根本辦法,就是明確指定整個(gè)應(yīng)用系統(tǒng)使用統(tǒng)一的字符編碼集.指定統(tǒng)一字符集時(shí),到底是采用ISO8859-1 、GBK還是UTF-8字符集呢?
(1)如果統(tǒng)一指定為ISO8859-1,運(yùn)行操作系統(tǒng)的默認(rèn)編碼必須是ISO8859-1,如Linux.因?yàn)槟壳按蠖鄶?shù)軟件都是西方人編制的,他們默認(rèn)的字符集就是ISO8859-1,包括操作系統(tǒng)Linux和數(shù)據(jù)庫MySQL等.然后需要將開發(fā)和編譯Java代碼[10]時(shí)的字符集指定為ISO8859-1,在JSP頁面的頭部增加字符編碼集的聲明.
(2)如果統(tǒng)一指定為GBK中文字符集,則系統(tǒng)只能運(yùn)行在默認(rèn)編碼為GBK的操作系統(tǒng),如中文Windows.其它設(shè)置同上.統(tǒng)一編碼為ISO8859-1和GBK雖然帶來編制代碼的方便,但是各自只能在相應(yīng)的操作系統(tǒng)上運(yùn)行,這也破壞了Java跨平臺(tái)運(yùn)行的優(yōu)越性,只在一定范圍內(nèi)行得通.例如,為了使得GBK編碼在Linux上運(yùn)行,設(shè)置Linux編碼為GBK.
(3)將系統(tǒng)的編碼統(tǒng)一定義為UTF-8,這是一種除了應(yīng)用系統(tǒng)以外不需要進(jìn)行任何附加設(shè)置的中文編碼正常顯示的根本解決方案.UTF-8編碼是一種兼容所有語言的編碼方式,唯一比較麻煩的就是要找到應(yīng)用系統(tǒng)的所有出入口,然后將其編碼方式設(shè)置成UTF-8.具體操作方法包括以下幾步:
①開發(fā)和編譯Java代碼時(shí)指定字符集為UTF-8,可以在開發(fā)工具JBuilder或MyEclipse的項(xiàng)目屬性中進(jìn)行設(shè)置.
②使用Servlet規(guī)范中的過濾器Filter統(tǒng)一指定編碼,使所有請(qǐng)求都經(jīng)過一個(gè)Servlet控制器進(jìn)行分發(fā),通過Servlet的Filter方法進(jìn)行過濾,將所有來自瀏覽器的請(qǐng)求(Request)中數(shù)據(jù)的字符編碼轉(zhuǎn)換為UTF-8,因?yàn)闉g覽器發(fā)過來的請(qǐng)求包根據(jù)瀏覽器所在的操作系統(tǒng)編碼可能是各種形式編碼.
③在所有JSP頁面頭部進(jìn)行字符編碼集的聲明:
<%@ page contentType="text/html;charset=GBK"%>.
④在所有的html代碼中,聲明其字符編碼集為UTF-8,將瀏覽器的編碼方式設(shè)為UTF-8.
⑤在數(shù)據(jù)庫連接方式中設(shè)定數(shù)據(jù)庫字符編碼集為UTF-8.例如,連接MYSQL時(shí)配置URL如下:jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8,一般數(shù)據(jù)庫都可以通過配置工具設(shè)置默認(rèn)的字符編碼集為UTF-8.
⑥其他和外界交互時(shí)能夠設(shè)定編碼的都統(tǒng)一設(shè)定其編碼集為UTF-8,例如讀取文件、操作XML文件等.
采用上述方法指定整個(gè)J2EE應(yīng)用系統(tǒng)使用統(tǒng)一的UTF-8字符編碼集,可有效地解決Java/J2EE程序的中文亂碼問題,除了應(yīng)用系統(tǒng)以外不需要進(jìn)行任何附加設(shè)置,世界各國的文字便能正常顯示,符合了Java程序跨平臺(tái)的特性和國際化的需求.而且UTF-8是一種不定長(zhǎng)的字符編碼,英文字符和HTML指令的網(wǎng)絡(luò)傳送效率較高.其缺點(diǎn)是UTF-8編碼需要字節(jié)數(shù)長(zhǎng)短不一致,搜索算法復(fù)雜,數(shù)據(jù)占用較大的存儲(chǔ)空間.
信息全球化使得多種字符編碼混用是必然的,同時(shí)會(huì)產(chǎn)生很多意想不到的問題.忽視字符編碼理論會(huì)導(dǎo)致數(shù)據(jù)庫系統(tǒng)出現(xiàn)嚴(yán)重的安全隱患[11].
最早的數(shù)據(jù)庫系統(tǒng)內(nèi)部使用ANSI或ISO8859-1編碼,雖然目前主流的數(shù)據(jù)庫系統(tǒng)都兼容了Unicode,但大多默認(rèn)采用ISO8859-1字符編碼,不同編碼之間轉(zhuǎn)換時(shí)可能引起字符丟失.
在設(shè)計(jì)數(shù)據(jù)庫系統(tǒng)時(shí),應(yīng)該盡量使用先進(jìn)的Unicode,以提高字符兼容性.同時(shí)應(yīng)充分掌握這3種常用的字符編碼理論,有效地使用字符編碼知識(shí),提高數(shù)據(jù)庫系統(tǒng)的網(wǎng)絡(luò)數(shù)據(jù)傳送效率,并充分利用存貯空間.
[1] 許 成,李茂青.Unicode數(shù)據(jù)倉庫ETL的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)工程,2008,34(11):74-76.
[2] 李建文,張成現(xiàn).實(shí)用網(wǎng)絡(luò)通信編程技術(shù)[M].北京:北京郵電大學(xué)出版社,2006:25-56.
[3] 童天添.基于C#的字符編碼映射系統(tǒng)[J].陜西科技大學(xué)學(xué)報(bào)(自然科學(xué)版),2010,28(4):96-99.
[4] 維尼拉·木沙江,吐爾地·托合提,吐爾洪·吾司曼.基于重定位的維、哈、柯文Unicode編碼及多文種索引技術(shù)研究[J].鄭州大學(xué)學(xué)報(bào)(理學(xué)版),2009,41(1):48-55.
[5] 吳道榮,王善發(fā).獲取Unicode字符集中漢字的拼音和內(nèi)碼[J].現(xiàn)代電子技術(shù),2009,32(16):83-85.
[6] 唐小新.基于Unicode字符集數(shù)據(jù)遷移的設(shè)計(jì)與實(shí)現(xiàn)[J].企業(yè)科技與發(fā)展,2011(17):22-24.
[7] 包竹葦,李 淼,張 建.Java網(wǎng)絡(luò)傳輸中字符編碼問題的研究[J].計(jì)算機(jī)工程與應(yīng)用,2007,43(4):93-95.
[8] 范道爾吉,白鳳山,武慧娟.基于Unicode編碼的蒙古文輸入法研究[J].中文信息學(xué)報(bào),2010,24(6):120-124,128.
[9] 李培峰,朱巧明,錢培德.一個(gè)基于ISO/IEC10646的漢字輸入模型[J].中文信息學(xué)報(bào),2006,20(5):91-96.
[10] 費(fèi)玉奎.基于Servlet的漢字信息處理方法[J].計(jì)算機(jī)工程,2000,26(10):173.
[11] 黃鶴鳴,趙晨星.藏文字符集基本集的修訂方案[J].計(jì)算機(jī)工程與應(yīng)用,2007,43(20):187-189,193.