<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/tips/15129

                    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)合法輸入:

                    #!sql
                    id=1
                    SELECT * FROM users WHRER id='1';
                    

                    (2)惡意注入:

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

                    2、Java代碼分析(JDBC)

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

                    #!java
                    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指向要訪問的數據庫名mydata
                            String 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("數據庫數據成功獲取!!");
                            }
                        }
                    }
                    

                    執行結果:

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

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

                    #!java
                    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指向要訪問的數據庫名mydata
                            String 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("數據庫數據成功獲取!!");
                            }
                        }
                    }
                    

                    執行結果:

                    #!shell
                    SQL Paramter:1
                    -----------------
                    budi    27
                    -----------------
                    SQL Paramter:' or 'a'='a
                    -----------------
                    -----------------
                    

                    3、防范建議:

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

                    0x02 XML注入


                    1、原理

                    (1)合法輸入:

                    #!xml
                    quantity=1
                    <item>
                        <name>apple</name>
                        <price>500.0</price>
                        <quantity>1</quantity>
                    <item>
                    

                    (2)惡意輸入:

                    #!xml
                    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)不合規代碼(未進行安全檢查)

                    #!java
                    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;
                        }
                    }
                    

                    運行結果:

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

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

                    #!xml
                    <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>
                    

                    測試代碼

                    #!java
                    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("解析異常");
                            }
                        }
                    }
                    

                    運行結果:

                    #!shell
                    正常輸入........
                    解析正常
                    惡意輸入........
                    錯誤: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
                    <?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
                    <?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)不合規代碼(未安全檢查外部實體)

                    #!java
                    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());
                        }  
                    }
                    

                    運行結果:

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

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

                    #!java
                    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();
                            }
                        }
                    }
                    

                    測試代碼

                    #!java
                    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 block
                                System.out.println("\t非法解析!");
                            } catch (SAXException e) {
                                // TODO Auto-generated catch block
                                System.out.println("\t非法解析!");
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                System.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());
                        }
                    }
                    

                    運行結果:

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

                    3、防范建議:

                    √ 白名單

                    0x04命令注入


                    1、原理:

                    (1)正常輸入:

                    #!shell
                    dir
                    

                    (2)惡意輸入:

                    #!shell
                    dir & ipconfig & net user budi budi /add & net localgroup Administrators admin /add
                    

                    2、Java代碼分析

                    (1)非合規Window命令注入

                    #!java
                    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注入命令

                    #!java
                    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)合規編碼(對命令安全檢查)

                    #!java
                    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)合法輸入:

                    #!shell
                    普通壓縮比文件normal.zip
                    

                    (2)惡意輸入:

                    #!shell
                    高壓縮比文件evil.zip
                    

                    2、Java代碼分析

                    #!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) + " 豪秒");
                        }
                    }
                    

                    運行結果:

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

                    (2)合規代碼

                    #!java
                    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) + " 豪秒");
                        }
                    }
                    

                    運行結果:

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

                    3、防范建議:

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

                    0x06 正則表達式注入


                    1、原理:

                    (1)合法輸入

                    #!shell
                    search=error
                    

                    拼接后

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

                    (2)惡意輸入

                    #!shell
                    search=.*)|(.*
                    

                    拼接后

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

                    2、Java代碼分析

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

                    #!java
                    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",".*)|(.*");
                        }
                    }
                    

                    運行結果:

                    #!shell
                    正常輸入......
                    正則表達式:(.*? +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)合規代碼(進行安全檢查)

                    #!java
                    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",".*)|(.*");
                        }
                    }
                    

                    運行結果:

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

                    3、防范建議:

                    √ 白名單

                    0x07 未凈化輸入


                    (1)日志記錄

                    正常輸入:

                    #!shell
                    budi
                    

                    日志記錄:

                    #!shell
                    User Login Successed for: budi
                    

                    惡意輸入:

                    #!shell
                    budi \nUser Login Successed for: administrator
                    

                    日志記錄:

                    #!shell
                    User Login Failed for: budi 
                    User Login Successed for: administrator
                    

                    (2)更新用戶名

                    正常輸入:

                    #!sql
                    username=budi
                    

                    SQL查詢:

                    #!sql
                    SELECT * FROM users WHRER id='budi';
                    

                    惡意輸入:

                    #!sql
                    username=budi' or 'a'='a
                    

                    SQL查詢:

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

                    2、Java代碼分析

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

                    #!java
                    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);
                        }
                    }
                    

                    運行結果:

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

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

                    #!java
                    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);
                        }
                    }
                    

                    運行結果:

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

                    3、防范建議:

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

                    0x08 路徑遍歷


                     1、原理:

                    (1)正常輸入:

                    #!shell
                    john.txt
                    

                    (2)惡意輸入:

                    #!shell
                    ../../a.txt"
                    

                    2、Java代碼分析

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

                    #!java
                    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;
                        }
                    }
                    

                    運行結果:

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

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

                    #!java
                    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;
                        }
                    }
                    

                    運行結果:

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

                    3、防范建議

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

                    0x09 格式化字符串


                    1、原理:

                    (1)正常輸入:

                    11

                    正常拼接:

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

                    (2)惡意輸入:

                    #!shell
                    %1$tm或%1$te或%1$tY
                    

                    惡意拼接:

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

                    2、Java代碼分析

                    (1)非合規代碼:

                    #!java
                    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);
                        }
                    }
                    

                    運行結果:

                    #!shell
                    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)合規代碼:

                    #!java
                    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);
                        }
                    }
                    

                    運行結果:

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

                    3、防范建議:

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

                    0x0A 字符串標準化


                    1、原理:

                    (1)合法輸入:

                    #!shell
                    username=budi
                    

                    (2)惡意輸入一:

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

                    (3)惡意輸入二:

                    #!shell
                    username=A\uD8AB
                    username=A?
                    

                    2、Java代碼分析

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

                    #!java
                    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);
                        }
                    }
                    

                    運行結果:

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

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

                    #!java
                    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+"->合法字符");
                            }
                        }
                    }
                    

                    運行結果:

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

                    3、防范建議:

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

                    0x0B 最后總結


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

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频