日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java安全编码之用户输入

發布時間:2024/1/17 java 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java安全编码之用户输入 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

0x00 安全引言


1、傳統Web應用與新興移動應用

(1)傳統Web應用:瀏覽器 HTTP 服務器
(2)新興移動應用:APP HTTP 服務器

從安全角度看,傳統Web應用與新興移動應用沒有本質區別

2、Web應用安全的核心問題是什么?

用戶提交的數據不可信是Web應用程序核心安全問題

用戶可以提交任意輸入

例如:

√ 請求參數->多次提交或者不提交
√ 修改Cookie
√ 修改HTTP信息頭
√ 請求順序->跳過或者打亂

3、Web應用防御

(1)完善的異常處理
(2)監控
(3)日志:記錄重要業務、異常的詳細請求信息

4、對輸入的處理

建議采用:白名單
盡量避免:凈化或黑名單

0x01 SQL注入


1、原理:

(1)合法輸入:

id=1 SELECT * FROM users WHRER id='1';

?

(2)惡意注入:

id=1' or '1'='1 SELECT * FROM users WHRER id='1' or 'a'='a';

2、Java代碼分析(JDBC)

(1)不合規代碼(SQL參數拼接)

public class SQLInject {public static void main(String[] args)throws Exception{//正常輸入select("1");// 惡意輸入select("' or 'a'='a");}public static void select(String id){//聲明Connection對象 Connection con;//驅動程序名String driver = "com.mysql.jdbc.Driver";//URL指向要訪問的數據庫名mydataString url = "jdbc:mysql://localhost:3306/mybatis";//MySQL配置時的用戶名String user = "root";//MySQL配置時的密碼String password = "budi";//遍歷查詢結果集try {//加載驅動程序 Class.forName(driver);//1.getConnection()方法,連接MySQL數據庫!!con = DriverManager.getConnection(url,user,password);if(!con.isClosed())System.out.println("Succeeded connecting to the Database!");//2.創建statement類對象,用來執行SQL語句!!Statement statement = con.createStatement();//要執行的SQL語句String sql = "select * from users where id='"+id+"'";//3.ResultSet類,用來存放獲取的結果集!!ResultSet rs = statement.executeQuery(sql);System.out.println("-----------------");System.out.println("執行結果如下所示:"); System.out.println("-----------------");String age,name;while(rs.next()){//獲取stuname這列數據name = rs.getString("name");//獲取stuid這列數據age = rs.getString("age");//輸出結果System.out.println(name + "\t" + age);}rs.close();con.close();} catch(ClassNotFoundException e) { //數據庫驅動類異常處理System.out.println("Sorry,can`t find the Driver!"); e.printStackTrace(); } catch(SQLException e) {//數據庫連接失敗異常處理 e.printStackTrace(); }catch (Exception e) {// TODO: handle exception e.printStackTrace();}finally{System.out.println("數據庫數據成功獲取!!");}} }

?

執行結果:

SQL Paramter:1 ----------------- budi 27 ----------------- SQL Paramter:' or 'a'='a ----------------- budi 27 budisploit 28 -----------------

?

(2)合規代碼(參數化查詢)

public class SQLFormat {public static void main(String[] args)throws Exception{select("1");select("' or 'a'='a");}public static void select(String id){//聲明Connection對象 Connection con;//驅動程序名String driver = "com.mysql.jdbc.Driver";//URL指向要訪問的數據庫名mydataString url = "jdbc:mysql://localhost:3306/mybatis";//MySQL配置時的用戶名String user = "root";//MySQL配置時的密碼String password = "budi";//遍歷查詢結果集try {//加載驅動程序 Class.forName(driver);//1.getConnection()方法,連接MySQL數據庫!!con = DriverManager.getConnection(url,user,password);if(!con.isClosed())System.out.println("Succeeded connecting to the Database!");//2.//要執行的SQL語句String sql = "select * from users where id=?";//3.創建statement類對象,ResultSet類,用來存放獲取的結果集!!PreparedStatement stmt = con.prepareStatement(sql);stmt.setString(1, id);ResultSet rs = stmt.executeQuery();System.out.println("-----------------");System.out.println("執行結果如下所示:"); System.out.println("-----------------");String age,name;while(rs.next()){//獲取stuname這列數據name = rs.getString("name");//獲取stuid這列數據age = rs.getString("age");//輸出結果System.out.println(name + "\t" + age);}rs.close();con.close();} catch(ClassNotFoundException e) { //數據庫驅動類異常處理System.out.println("Sorry,can`t find the Driver!"); e.printStackTrace(); } catch(SQLException e) {//數據庫連接失敗異常處理 e.printStackTrace(); }catch (Exception e) {// TODO: handle exception e.printStackTrace();}finally{System.out.println("數據庫數據成功獲取!!");}} } View Code

?

執行結果:

SQL Paramter:1 ----------------- budi 27 ----------------- SQL Paramter:' or 'a'='a ----------------- -----------------

?

3、防范建議:

√ 采用參數查詢即預編譯方式(首選)
√ 字符串過濾

0x02 XML注入


1、原理

(1)合法輸入:

quantity=1 <item><name>apple</name><price>500.0</price><quantity>1</quantity> <item>

?

(2)惡意輸入:

quantity=1</quantity><price>5.0</price><quantity>1 <item><name>apple</name><price>500.0</price><quantity>1</quantity><price>5.0</price><quantity>1</quantity> <item>

?

2、Java代碼分析

(1)不合規代碼(未進行安全檢查)

public class XMLInject2 {public static void main(String[] args) {// 正常輸入ArrayList<Map<String, String>> normalList=(ArrayList<Map<String, String>>)ReadXML("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\xml\\inject\\normal.xml","price");System.out.println(normalList.toString());// 異常輸入ArrayList<Map<String, String>> evilList=(ArrayList<Map<String, String>>)ReadXML("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\xml\\inject\\evil.xml","price");System.out.println(evilList.toString());}private static List<Map<String,String>> ReadXML(String uri,String NodeName){try {//創建一個解析XML的工廠對象SAXParserFactory parserFactory=SAXParserFactory.newInstance();//創建一個解析XML的對象SAXParser parser=parserFactory.newSAXParser();//創建一個解析助手類MyHandler myhandler=new MyHandler(NodeName);parser.parse(uri, myhandler);return myhandler.getList();} catch (Exception e) {e.printStackTrace();}return null;} }

?

運行結果:

正常輸入結果:[{price=500.0}] 惡意輸入結果:[{price=500.0}, {price=5.0}]

?

(2)合規代碼(利用schema安全檢查)

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="item"><xs:complexType><xs:sequence><xs:element name="name" type="xs:string"/><xs:element name="price" type="xs:decimal"/><xs:element name="quantity" type="xs:integer"/></xs:sequence></xs:complexType> </xs:element>

?

測試代碼

public class XMLFormat{public static void main(String[] args) {//測試正常輸入test("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\xml\\inject\\normal.xml");//測試異常輸入test("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\xml\\inject\\evil.xml");}private static void test(String file) {SchemaFactory schemaFactory = SchemaFactory.newInstance("XMLConstants.W3C_XML_SCHEMA_NS_URI");Schema schema;try {schema = schemaFactory.newSchema(new File("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\xml\\inject\\schema.xsd"));Validator validator = schema.newValidator();validator.setErrorHandler(new ErrorHandler() {public void warning(SAXParseException exception)throws SAXException {System.out.println("警告:" + exception);}public void fatalError(SAXParseException exception)throws SAXException {System.out.println("致命:" + exception);}public void error(SAXParseException exception) throws SAXException {System.out.println("錯誤:" + exception);}});validator.validate(new StreamSource(new File(file)));System.out.println("解析正常");;} catch (SAXException e) {// TODO Auto-generated catch block//e.printStackTrace();System.out.println("解析異常");} catch (IOException e) {// TODO Auto-generated catch block//e.printStackTrace();System.out.println("解析異常");}} }

?

運行結果:

正常輸入........ 解析正常 惡意輸入........ 錯誤:org.xml.sax.SAXParseException; systemId: file:/D:/JavaWorkspace/TestInput/src/cn/com/budi/xml/inject/evil.xml; lineNumber: 7; columnNumber: 10; cvc-complex-type.2.4.d: 發現了以元素 'price' 開頭的無效內容。此處不應含有子元素。

?

3、防范建議:

√ 文檔類型定義(Document Type Definition,DTD)
√ XML結構化定義文件(XML Schemas Definition)
√ 白名單

0x03 XXE (XML external entity)


1、原理:

(1)合法輸入:

<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE updateProfile [<!ENTITY lastname "Hello, Budi!"> <!ENTITY file SYSTEM "file:///D:/test.txt">]> <users ><firstname>&file</firstname><lastname>&lastname;</lastname> </users>

?

(2)惡意輸入:

<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE updateProfile [<!ENTITY file SYSTEM "file:///D:/password.txt"> ]> <users ><firstname>&file;</firstname><lastname>&lastname;</lastname> </users>

?

2、Java代碼分析

(1)不合規代碼(未安全檢查外部實體)

public class XXEInject {private static void receiveXMLStream(InputStream inStream, MyDefaultHandler defaultHandler) {// 1.獲取基于SAX的解析器的實例SAXParserFactory factory = SAXParserFactory.newInstance();// 2.創建一個SAXParser實例SAXParser saxParser = factory.newSAXParser();// 3.解析 saxParser.parse(inStream, defaultHandler);}public static void main(String[] args) throws FileNotFoundException, ParserConfigurationException, SAXException, IOException{//正常輸入receiveXMLStream(new FileInputStream("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\xml\\xxe\\inject\\normal.xml"), new MyDefaultHandler());//惡意輸入receiveXMLStream(new FileInputStream("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\xml\\xxe\\inject\\evil.xml"),new MyDefaultHandler());} }

?

運行結果:

正常輸入,等待解析...... <firstname>XEE TEST !!</firstname> ========================== 惡意輸入,等待解析...... <firstname>OWASP BWA root/owaspbwa Metasploitable msfadmin/msfadmin Kali Liunx root/wangpeng </firstname>

?

(2)合規代碼(安全檢查外部實體)

public class CustomResolver implements EntityResolver{public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException{//System.out.println("PUBLIC:"+publicId);//System.out.println("SYSTEM:"+systemId);System.out.println("引用實體檢測....");String entityPath = "file:///D:/test.txt";if (systemId.equals(entityPath)){System.out.println("合法解析:"+systemId);return new InputSource(entityPath);}else{System.out.println("非法實體:"+systemId);return new InputSource();}} }

?

測試代碼

public class XXEFormat {private static void receiveXMLStream(InputStream inStream, MyDefaultHandler defaultHandler) {// 獲取基于SAX的解析器的實例SAXParserFactory factory = SAXParserFactory.newInstance();// 創建一個SAXParser實例 SAXParser saxParser;try {saxParser = factory.newSAXParser();//創建讀取工具XMLReader reader = saxParser.getXMLReader();reader.setEntityResolver(new CustomResolver());reader.setErrorHandler(defaultHandler);InputSource is = new InputSource(inStream);reader.parse(is);System.out.println("\t成功解析完成!");} catch (ParserConfigurationException e) {// TODO Auto-generated catch blockSystem.out.println("\t非法解析!");} catch (SAXException e) {// TODO Auto-generated catch blockSystem.out.println("\t非法解析!");} catch (IOException e) {// TODO Auto-generated catch blockSystem.out.println("\t非法解析!");}}public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException{//正常輸入System.out.println("正常輸入,等待解析......");receiveXMLStream(new FileInputStream("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\xml\\xxe\\inject\\normal.xml"), new MyDefaultHandler());System.out.println("==========================");//惡意輸入System.out.println("惡意輸入,等待解析......");receiveXMLStream(new FileInputStream("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\xml\\xxe\\inject\\evil.xml"), new MyDefaultHandler());} }

?

運行結果:

正常輸入,等待解析...... 引用實體檢測.... 合法解析:file:///D:/test.txt成功解析完成! ========================== 惡意輸入,等待解析...... 引用實體檢測.... 非法實體:file:///D:/password.txt非法解析!

?

3、防范建議:

√ 白名單

0x04命令注入


1、原理:

(1)正常輸入:

dir

?

(2)惡意輸入:

dir & ipconfig & net user budi budi /add & net localgroup Administrators admin /add

?

2、Java代碼分析

(1)非合規Window命令注入

public class OrderWinFault {public static void main(String[] args) throws Exception{//正常命令runOrder("dir");//惡意命令runOrder("dir & ipconfig & net user budi budi /add & net localgroup Administrators admin /add");}private static void runOrder(String order) throws IOException, InterruptedException{Runtime rt = Runtime.getRuntime();Process proc = rt.exec("cmd.exe /C "+order);int result = proc.waitFor();if(result !=0){System.out.println("process error: "+ result);}InputStream in = (result == 0)? proc.getInputStream() : proc.getErrorStream();BufferedReader reader=new BufferedReader(new InputStreamReader(in));StringBuffer buffer=new StringBuffer();String line;while((line = reader.readLine())!=null){buffer.append(line+"\n");}System.out.print(buffer.toString());} }

?

(2)非合規的Linux注入命令

public class OrderLinuxFault {public static void main(String[] args) throws Exception{// 正常命令runOrder("ls");// 惡意命令runOrder(" ls & ifconfig");}private static void runOrder(String order) throws IOException, InterruptedException{Runtime rt = Runtime.getRuntime();Process proc = rt.exec(new String [] {"sh", "-c", "ls "+order});int result = proc.waitFor();if(result !=0){System.out.println("process error: "+ result);}InputStream in = (result == 0)? proc.getInputStream() : proc.getErrorStream();BufferedReader reader=new BufferedReader(new InputStreamReader(in));StringBuffer buffer=new StringBuffer();String line;while((line = reader.readLine())!=null){buffer.append(line+"\n");}System.out.print(buffer.toString());} }

?

(3)合規編碼(對命令安全檢查)

public class OrderFormat {public static void main(String[] args) throws Exception{runOrder("dir");runOrder("dir & ipconfig & net user budi budi /add & net localgroup Administrators admin /add");}private static void runOrder(String order) throws IOException, InterruptedException{if (!Pattern.matches("[0-9A-Za-z@.]+", order)){System.out.println("存在非法命令");return;}Runtime rt = Runtime.getRuntime();Process proc = rt.exec("cmd.exe /C "+order);int result = proc.waitFor();if(result !=0){System.out.println("process error: "+ result);}InputStream in = (result == 0)? proc.getInputStream() : proc.getErrorStream();BufferedReader reader=new BufferedReader(new InputStreamReader(in));StringBuffer buffer=new StringBuffer();String line;while((line = reader.readLine())!=null){buffer.append(line+"\n");}System.out.print(buffer.toString());} }

3、防范建議:

√ 白名單
√ 嚴格權限限制
√ 采用命令標號

0x05 壓縮炸彈(zip bomb)


(1)合法輸入:

普通壓縮比文件normal.zip

(2)惡意輸入:

高壓縮比文件evil.zip

2、Java代碼分析

public class ZipFault {static final int BUFFER = 512;public static void main(String[] args) throws IOException{System.out.println("正常壓縮文件.......");checkzip("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\zip\\normal.zip");System.out.println("惡意壓縮文件.......");checkzip("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\zip\\evil.zip");}private static void checkzip(String filename) throws IOException{BufferedOutputStream dest = null;FileInputStream fls = new FileInputStream(filename);ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fls));ZipEntry entry;long begin = System.currentTimeMillis(); while ((entry = zis.getNextEntry()) != null){System.out.println("Extracting:" + entry+"\t解壓后大小:"+entry.getSize());int count;byte data[] = new byte[BUFFER];FileOutputStream fos = new FileOutputStream("D:/"+entry.getName());dest = new BufferedOutputStream(fos, BUFFER);while ((count = zis.read(data, 0, BUFFER))!=-1){dest.write(data,0, count);}dest.flush();dest.close();}zis.close();long end = System.currentTimeMillis(); System.out.println("解壓縮執行耗時:" + (end - begin) + " 豪秒");} }

運行結果:

正常壓縮文件....... Extracting:normal.txt 解壓后大小:17496386 解壓縮執行耗時:382 豪秒 惡意壓縮文件....... Extracting:evil.txt 解壓后大小:2000000000 解壓縮執行耗時:25911 豪秒

(2)合規代碼

public class ZipFormat {static final int BUFFER = 512;static final int TOOBIG = 0x640000;public static void main(String[] args) throws IOException{checkzip("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\zip\\normal.zip");checkzip("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\zip\\evil.zip");}private static void checkzip(String filename) throws IOException{BufferedOutputStream dest = null;FileInputStream fls = new FileInputStream(filename);ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fls));ZipEntry entry;long begin = System.currentTimeMillis(); while ((entry = zis.getNextEntry()) != null){System.out.println("Extracting:" + entry+"\t解壓后大小:"+entry.getSize());if (entry.getSize() > TOOBIG){System.out.println("壓縮文件過大");break;}if (entry.getSize() == -1){System.out.println("文件大小異常");}int count;byte data[] = new byte[BUFFER];FileOutputStream fos = new FileOutputStream("D:/"+entry.getName());dest = new BufferedOutputStream(fos, BUFFER);while ((count = zis.read(data, 0, BUFFER))!=-1){dest.write(data,0, count);}dest.flush();dest.close();}zis.close();long end = System.currentTimeMillis(); System.out.println("解壓縮執行耗時:" + (end - begin) + " 豪秒");} }

運行結果:

正常文件......... Extracting:normal.txt 解壓后大小:17496386 解壓縮執行耗時:378 豪秒 =================== 惡意文件......... Extracting:evil.txt 解壓后大小:2000000000 壓縮文件過大 解壓縮執行耗時:0 豪秒

3、防范建議:

√ 解壓前檢查解壓后文件大小

0x06 正則表達式注入


1、原理:

(1)合法輸入

search=error

拼接后

(.*? +public\\[\\d+\\]+.*error.*)

(2)惡意輸入

search=.*)|(.*

拼接后

(.*? +public\\[\\d+\\]+.*.*)|(.*.*)

2、Java代碼分析

(1)非合規代碼(未進行安全檢查)

public class RegexFault {/*** 以行為單位讀取文件,常用于讀面向行的格式化文件*/public static void readFileByLines(String filename,String search) {File file = new File(filename);BufferedReader reader = null;String regex ="(.*? +public\\[\\d+\\] +.*"+search+".*)";System.out.println("正則表達式:"+regex);try {reader = new BufferedReader(new FileReader(file));String tempString = null;int line = 1;System.out.println("查找開始......");// 一次讀入一行,直到讀入null為文件結束while ((tempString = reader.readLine()) != null) {//System.out.println("line " + line + ": " + tempString);if(Pattern.matches(regex, tempString)){// 顯示行號System.out.println("line " + line + ": " + tempString);}line++;}reader.close();System.out.println("查找結束....");} catch (IOException e) {e.printStackTrace();} finally {if (reader != null) {try {reader.close();} catch (IOException e1) {}}}}public static void main(String[] args){//正常輸入readFileByLines("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\regex\\regex.log","error");//惡意輸入readFileByLines("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\regex\\regex.log",".*)|(.*");} }

?

運行結果:

正常輸入...... 正則表達式:(.*? +public\[\d+\] +.*error.*) line 5: 10:48:08 public[48964] Backup failed with error: 19 ============================ 惡意輸入...... 正則表達式:(.*? +public\[\d+\] +.*.*)|(.*.*) line 1: 10:47:03 private[423] Successful logout name: budi ssn: 111223333 line 2: 10:47:04 public[48964] Failed to resolve network service line 3: 10:47:04 public[1] (public.message[49367]) Exited with exit code: 255 line 4: 10:47:43 private[423] Successful login name: budisploit ssn: 444556666 line 5: 10:48:08 public[48964] Backup failed with error: 19

(2)合規代碼(進行安全檢查)

public class RegexFormat {/*** 檢測是否存在非法字符* @param search*/private static boolean validate(String search){for (int i = 0; i< search.length(); i++){char ch = search.charAt(i);if(!(Character.isLetterOrDigit(ch) || ch ==' ' || ch =='\'')){System.out.println("存在非法字符,查找失敗....");return false;}}return true;}/*** 以行為單位讀取文件,常用于讀面向行的格式化文件*/public static void readFileByLines(String filename,String search) {if(!validate(search)){return;}File file = new File(filename);BufferedReader reader = null;String regex ="(.*? +public\\[\\d+\\] +.*"+search+".*)";System.out.println("正則表達式:"+regex);try {reader = new BufferedReader(new FileReader(file));String tempString = null;int line = 1;System.out.println("查找開始......");// 一次讀入一行,直到讀入null為文件結束while ((tempString = reader.readLine()) != null) {//System.out.println("line " + line + ": " + tempString);if(Pattern.matches(regex, tempString)){// 顯示行號System.out.println("line " + line + ": " + tempString);}line++;}reader.close();System.out.println("查找結束....");} catch (IOException e) {e.printStackTrace();} finally {if (reader != null) {try {reader.close();} catch (IOException e1) {}}}}public static void main(String[] args){//正常輸入System.out.println("正常輸入......");readFileByLines("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\regex\\regex.log","error");System.out.println("============================");//惡意輸入System.out.println("惡意輸入......");readFileByLines("D:\\JavaWorkspace\\TestInput\\src\\cn\\com\\budi\\regex\\regex.log",".*)|(.*");} }

運行結果:

============================ 正常輸入...... 正則表達式:(.*? +public\[\d+\] +.*error.*) line 5: 10:48:08 public[48964] Backup failed with error: 19 ============================ 惡意輸入...... 存在非法字符,查找失敗....

?

3、防范建議:

√ 白名單

0x07 未凈化輸入


(1)日志記錄

正常輸入:

budi

日志記錄:

User Login Successed for: budi

惡意輸入:

budi \nUser Login Successed for: administrator

日志記錄:

User Login Failed for: budi User Login Successed for: administrator

(2)更新用戶名

正常輸入:

username=budi

SQL查詢:

SELECT * FROM users WHRER id='budi';

?

惡意輸入:

username=budi' or 'a'='a

?

SQL查詢:

SELECT * FROM users WHRER id='budi' or 'a'='a';

?

2、Java代碼分析

(1)非合規代碼(未安全檢查)

public class LogFault {private static void writeLog( boolean isLogin,String username){if(isLogin){System.out.println("User Login Successed for: "+username);}else{System.out.println("User Login Failed for: "+username);}}public static void main(String[] args){String test1= "budi";System.out.println("正常用戶登錄成功后,記錄日志.....");//正常用戶登錄成功后,記錄日志writeLog(true, test1);//惡意用戶登錄失敗,記錄日志String test2 = "budi \nUser Login Successed for: administrator";System.out.println("惡意用戶登錄失敗,記錄日志.....");writeLog(false, test2);} }

?

運行結果:

正常用戶登錄成功后,記錄日志..... User Login Successed for: budi 惡意用戶登錄失敗,記錄日志..... User Login Failed for: budi User Login Successed for: administrator

(2)合規代碼(安全檢查)

public class LoginFormat {private static void writeLog( boolean isLogin,String username){if(!Pattern.matches("[A-Za-z0-9_]+", username)){System.out.println("User Login Failed for Unknow User");}else if(isLogin){System.out.println("User Login Successed for: "+username);}else{System.out.println("User Login Failed for: "+username);}}public static void main(String[] args){String test1= "budi";System.out.println("正常用戶登錄成功后,記錄日志.....");writeLog(true, test1);String test2 = "budi \nUser Login Successed for: administrator";System.out.println("惡意用戶登錄失敗,記錄日志.....");writeLog(false, test2);} }

?

運行結果:

正常用戶登錄成功后,記錄日志..... User Login Successed for: budi 惡意用戶登錄失敗,記錄日志..... User Login Failed for Unknow User

3、防范建議:

√ 先檢測用戶輸入,強烈建議直接拒絕帶非法字符的數據

0x08 路徑遍歷


 1、原理:

(1)正常輸入:

john.txt

?

(2)惡意輸入:

../../a.txt"

2、Java代碼分析

(1)非合規代碼(未安全檢查)

public class PathFault {public static void main(String[] args) throws IOException{System.out.println("合法輸入.......");readFile("john.txt");System.out.println("\n惡意輸入.......");readFile("../../a.txt");}private static void readFile(String path) throws IOException{File f = new File("F://passwords//"+path);String absPath = f.getAbsolutePath();FileOutputStream fls = new FileOutputStream(f);System.out.print("絕對路徑:"+absPath);if(!isInSecureDir(Paths.get(absPath))){System.out.println("->非安全路徑");return;}System.out.print("->安全路徑");}private static boolean isInSecureDir(Path path){if(!path.startsWith("F://passwords//")){return false;};return true;} }

?

運行結果:

合法輸入....... 絕對路徑:F:\passwords\john.txt->安全路徑 惡意輸入....... 絕對路徑:F:\passwords\..\..\a.txt->安全路徑

?

(2)合規代碼(先統一路徑表示)

public class PathFormat {public static void main(String[] args) throws IOException{System.out.println("合法輸入.......");readFile("john.txt");System.out.println("/n惡意輸入.......");readFile("../../a.txt");}private static void readFile(String path) throws IOException{File f = new File("F://passwords//"+path);String canonicalPath = f.getCanonicalPath();System.out.println("絕對路徑"+canonicalPath);FileInputStream fls = new FileInputStream(f);if(!isInSecureDir(Paths.get(canonicalPath))){System.out.print("非安全路徑");return;}System.out.print("安全路徑");}private static boolean isInSecureDir(Path path){if(!path.startsWith("F://passwords//")){return false;};return true;} }

?

運行結果:

合法輸入....... 絕對路徑F:\passwords\john.txt->安全路徑 惡意輸入....... 絕對路徑F:\a.txt->非安全路徑

3、防范建議

√ 嚴格的權限限制->安全管理器
√ getCanonicalPath()在所有平臺上對所有別名、快捷方式、符號鏈接采用統一的解析。

0x09 格式化字符串


1、原理:

(1)正常輸入:

11

正常拼接:

System.out.printf("11 did not match! HINT: It was issued on %1$te rd of some month\n", c);?

(2)惡意輸入:

%1$tm或%1$te或%1$tY?

惡意拼接:

System.out.printf("%1$tm did not match! HINT: It was issued on %1$te rd of some month\n", c);?

2、Java代碼分析

(1)非合規代碼:

public class DateFault {static Calendar c = new GregorianCalendar(2016, GregorianCalendar.MAY, 23);public static void main(String[] args){//正常用戶輸入System.out.println("正常用戶輸入.....");format("11");System.out.println("非正常輸入獲取月份.....");format("%1$tm");System.out.println("非正常輸入獲取日.....");format("%1$te");System.out.println("非正常輸入獲取年份.....");format("%1$tY");}private static void format(String month){System.out.printf(month+" did not match! HINT: It was issued on %1$te rd of some month\n", c);} }

?

運行結果:

11 did not match! HINT: It was issued on 23rd of some month 非正常輸入獲取月份..... 05 did not match! HINT: It was issued on 23rd of some month 非正常輸入獲取日..... 23 did not match! HINT: It was issued on 23rd of some month 非正常輸入獲取年份..... 2016 did not match! HINT: It was issued on 23rd of some month

(2)合規代碼:

public class DateFormat {static Calendar c = new GregorianCalendar(2016, GregorianCalendar.MAY, 23);public static void main(String[] args){//正常用戶輸入System.out.println("正常用戶輸入.....");format("11");System.out.println("非正常輸入獲取月份.....");format("%1$tm");System.out.println("非正常輸入獲取日.....");format("%1$te");System.out.println("非正常輸入獲取年份.....");format("%1$tY");}private static void format(String month){System.out.printf("%s did not match! HINT: It was issued on %1$te rd of some month\n", month, c);} }

?

運行結果:

正常用戶輸入..... 11 did not match! HINT: It was issued on Exception in thread "main" java.util.IllegalFormatConversionException: e != java.lang.String?

3、防范建議:

√ 對用戶輸入進行安全檢查
√ 在格式字符串中,杜絕使用用戶輸入參數

0x0A 字符串標準化


1、原理:

(1)合法輸入:

username=budi

?

(2)惡意輸入一:

username=/><script>alert(1)</script> username=/\uFE65\uFE64script\uFE65alert(1) \uFE64/script\uFE65

(3)惡意輸入二:

username=A\uD8AB username=A?

2、Java代碼分析

(1)非合規代碼(先檢查再統一編碼)

public class EncodeFault {public static void main(String[] args){System.out.println("未編碼的非法字符");check("/><script>alert(2)</script>");System.out.println("Unicode編碼的非法字符");check("/\uFE65\uFE64script\uFE65alert(1) \uFE64/script\uFE65");}public static void check(String s){Pattern pattern = Pattern.compile("[<>]");Matcher matcher = pattern.matcher(s);if (matcher.find()){System.out.println(s+"->存在非法字符");}else{System.out.println(s+"->合法字符");}s = Normalizer.normalize(s, Form.NFC);} }

?


運行結果:

未編碼的非法字符 /><script>alert(2)</script>->存在非法字符 Unicode編碼的非法字符 /﹥﹤script﹥alert(1) ﹤/script﹥->合法字符

?

(3)合規代碼(先統一編碼再檢查)

public class EncodeFormat {public static void main(String[] args){System.out.println("未編碼的非法字符");check("/><script>alert(2)</script>");System.out.println("Unicode編碼的非法字符");check("/\uFE65\uFE64script\uFE65alert(1)\uFE64/script\uFE65");}public static void check(String s){s = Normalizer.normalize(s, Form.NFC);// 用\uFFFD替代非Unicode編碼字符s = s.replaceAll("^\\p{ASCII}]", "\uFFFD");Pattern pattern = Pattern.compile("[<>]");Matcher matcher = pattern.matcher(s);if (matcher.find()){System.out.println(s+"->存在非法字符");}else{System.out.println(s+"->合法字符");}} }

?

運行結果:

未編碼的非法字符 /><script>alert(2)</script>->存在非法字符 Unicode編碼的非法字符 /><script>alert(1)</script>->存在非法字符

?

3、防范建議:

√ 先按指定編碼方式標準化字符串,再檢查非法輸入
√ 檢測非法字符

0x0B 最后總結


  • 從安全角度看,移動應用與傳統Web應用沒有本質區別。
  • 安全的Web應用必須處理好兩件事:
  • 處理好用戶的輸入(HTTP請求)
  • 處理好應用的輸出(HTTP響應)

參考文獻: 《Java安全編碼標準》

總結

以上是生活随笔為你收集整理的Java安全编码之用户输入的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。