Javaセキュリティコーディングガイド:入力インジェクションインジェクション

前書き

インジェクションの問題はセキュリティで非常に一般的な問題です。今日は、JavaでのSQLインジェクションとXMLインジェクションの防止について説明します。

SQLインジェクション

SQLインジェクションとは何ですか?

SQLインジェクションとは、ユーザーが特定のパラメーターを入力することを意味します。これにより、最終的にSQLの実行がプログラマーの本来の意図から逸脱し、不正なエラーやその他のタイプのエラーが発生します。

つまり、ユーザー入力によってSQLの意味が変わったということです。

最も一般的に使用されるログインSQLステートメントを使用すると、次のSQLステートメントを記述できます。

select * from user where username='<username>' and password='<password>'

ユーザーがユーザー名とパスワードを渡す必要があります。

このSQLステートメントを挿入する方法は?

ユーザーのユーザー名入力が次の場合、非常に簡単です。

somebody' or '1'='1

次に、SQLステートメント全体が次のようになります。

select * from user where username='somebody' or '1'='1' and password='<password>'

誰かが有効なユーザーである場合、背後にある言語が実行されるか、まったく実行されないため、パスワードを確認せずにユーザーの情報が返されます。

同様に、悪意のある攻撃者は、パスワードに次のコンテンツを入力して同じ結果を得ることができます。

' or '1'='1

SQL全体は次のように解析されます。

select * from user where username='somebody' and password='' or '1'='1'

このステートメントはすべてのユーザー情報を返すため、存在するユーザー名がわからなくても、SQLステートメントで判断できます。

これはSQLインジェクションです。

javaでのSQLインジェクション

javaで最も一般的に使用されるのは、JDBCを介してデータベースを操作することです。JDBCを使用して接続を作成した後、SQLステートメントを実行できます。

javaでJDBCSQLインジェクションを使用する例を見てみましょう。

まず、一般的なJDBC接続を作成します。

    public Connection getConnection() throws ClassNotFoundException, SQLException {
    
    
        Connection con = null;
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("数据库驱动加载成功");
            con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8", "root", "");
            System.out.println("数据库连接成功");
          return con;
    }

次に、SQLステートメントを自分でアセンブルして、次を呼び出します。

public void jdbcWithInjection(String username,char[] password) throws SQLException, ClassNotFoundException {
    
    
        Connection connection = getConnection();
        if (connection == null) {
    
    
            // Handle error
        }
        try {
    
    
            String pwd = encodePassword(password);

            String sqlString = "SELECT * FROM user WHERE username = '"
                    + username +
                    "' AND password = '" + pwd + "'";
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery(sqlString);

            if (!rs.next()) {
    
    
                throw new SecurityException(
                        "User name or password incorrect"
                );
            }
        } finally {
    
    
            try {
    
    
                connection.close();
            } catch (SQLException x) {
    
    
            }
        }
    }

上記の例では、encodePasswordメソッドを使用してパスワードを変換したため、ユーザー名のみが挿入され、パスワードは挿入されません。

public String encodePassword(char[] password){
    
    
        return Base64.getEncoder().encodeToString(new String(password).getBytes());
    }

PreparedStatementを使用する

SQLインジェクションを防ぐために、通常、PreparedStatementを使用することをお勧めします。java.sql.PreparedStatementは入力パラメーターをエスケープしてSQLインジェクションを防ぐことができます。

PreparedStatementは正しく使用する必要があることに注意してください。正しく使用しないと、SQLインジェクションも発生します。

誤った使用例を見てみましょう。

String sqlString = "SELECT * FROM user WHERE username = '"
                    + username +
                    "' AND password = '" + pwd + "'";
            PreparedStatement stmt = connection.prepareStatement(sqlString);
            ResultSet rs = stmt.executeQuery();

上記のコードでは、SQLを自分でアセンブルしました。最終的にpreparedStatementを使用しましたが、効果は得られませんでした。

正しい使用例は次のとおりです。

String sqlString =
                    "select * from user where username=? and password=?";
            PreparedStatement stmt = connection.prepareStatement(sqlString);
            stmt.setString(1, username);
            stmt.setString(2, pwd);
            ResultSet rs = stmt.executeQuery();

ユーザー入力をパラメーターとしてPreparedStatementに設定して、エスケープできるようにする必要があります。

XMLでのSQLインジェクション

Extensible Markup Language(XML)は、データの保存、構造化、および送信を支援するように設計されています。プラットフォームの独立性、柔軟性、および比較的単純なため、XMLは多くのアプリケーションで使用されてきました。ただし、XMLは多様性があるため、XMLインジェクションを含むさまざまな攻撃に対して脆弱です。

では、XMLインジェクションとは何ですか?例を挙げましょう:

<item>
  <name>Iphone20</name>
  <price>5000.0</price>
  <quantity>1</quantity>
</item>

上記の例では、XMLを使用してiphone20の価格と数量を定義しました。iphone20は5000元です。

上記のXMLで、数量がユーザーによって入力されたデータである場合、ユーザーは次のように入力できます。

1</quantity><price>20.0</price><quantity>1

最終的なXMLファイルは次のとおりです。

<item>
  <name>Iphone20</name>
  <price>5000.0</price>
  <quantity>1</quantity>
  <price>20.0</price><quantity>1</quantity>
</item>

一般的に、XMLを解析する過程で、重複するタグが見つかった場合、次のタグが前のタグを上書きします。

その結果、iphone20の現在の価格は20元であり、非常に費用対効果が高くなっています。

XML注入されたJavaコード

XMLインジェクションがJavaコードでどのように実装されているかを見てみましょう。

    public String createXMLInjection(String quantity){
    
    
        String xmlString = "<item>\n<name>Iphone20</name>\n"
                + "<price>5000.0</price>\n" + "<quantity>" + quantity
                + "</quantity></item>";
        return xmlString;
    }

ユーザーが入力した量をXMLスプライシングとして直接使用していることがわかりますが、これは明らかに問題があります。

それを解決する方法は?2つの方法があります。

  • 最初の方法

最初の方法は、ユーザーが入力した数量を確認することです。

    public String createXML(String quantity){
    
    
        int count = Integer.parseUnsignedInt(quantity);
        String xmlString = "<item>\n<name>Iphone20</name>\n"
                + "<price>5000.0</price>\n" + "<quantity>" + count
                + "</quantity></item>";
        return xmlString;
    }

上記のコードでは、ユーザーによる不正な入力を避けるために、数量を整数に変換しました。

  • 2番目の方法

2番目の方法は、XMLスキーマを使用して、生成されたXMLの形式を確認することです。

この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:nonNegativeInteger"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>
</xs:schema>

上記では、XML要素のシーケンスを定義しました。ユーザーが未定義の形式で他のXMLを入力すると、エラーが報告されます。

対応するJavaコードの書き方を見てみましょう。

StreamSource ss = new StreamSource(new File("schema.xsd"));
            Schema schema = sf.newSchema(ss);
            SAXParserFactory spf = SAXParserFactory.newInstance();
            spf.setSchema(schema);
            SAXParser saxParser = spf.newSAXParser();
            XMLReader reader = saxParser.getXMLReader();
            reader.setContentHandler(defHandler);
            reader.parse(xmlStream);

上記のXML検証用のコードをリストしました。完全なコードについては、記事の最後にあるコードリンクを参照してください。ここでは、それらを1つずつ投稿しません。

この記事のコード:

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

この記事はhttp://www.flydean.com/java-security-code-line-injection/に含まれています

最も人気のある解釈、最も深遠な乾物、最も簡潔なチュートリアル、そしてあなたが知らない多くのヒントがあなたが発見するのを待っています!

私の公式アカウントに注意を払うことを歓迎します:「それらのものをプログラムする」、技術を知っている、あなたをもっとよく知っている!

おすすめ

転載: blog.csdn.net/superfjj/article/details/109021091