コードの質が低いと、予測できない動作につながります。ユーザーの視点には、それがしばしば使い勝手の悪さとなって現れます。攻撃者にとっては、予期せぬ方法でシステムにストレスを与える機会となります。
<script>
タグが含まれているかを判定するための検証を実行しています。
...
public String tagProcessor(String tag){
if (tag.toUpperCase().equals("SCRIPT")){
return null;
}
//does not contain SCRIPT tag, keep processing input
...
}
...
Example 1
の問題は、ロケールを指定せずに java.lang.String.toUpperCase()
を使用した場合、デフォルトのロケールを使用するルールが適用されることです。トルコ語ロケールを使用すると "title".toUpperCase()
は "T\u0130TLE" を返します。ここで "\u0130" は、"上に点が付いたラテン語の大文字 I" になります。これは、Example 1
のように "script" という単語が検証でキャッチされないなどの予期しない結果につながる場合があり、クロスサイト スクリプティングの脆弱性を引き起こす可能性があります。
...
import java.sql.PreparedStatement;
import com.sap.sql.NativeSQLAccess;
String mssOnlyStmt = "...";
// variant 1
PreparedStatement ps =
NativeSQLAccess.prepareNativeStatement(
conn, mssOnlyStmt);
. . .
// variant 2
Statement stmt =
NativeSQLAccess.createNativeStatement(conn);
int result = stmt.execute(mssOnlyStmt);
. . .
// variant 3
CallableStatement cs =
NativeSQLAccess.prepareNativeCall(
conn, mssOnlyStmt);
. . .
...
public class Box{
public int area;
public static final int width = 10;
public static final Box box = new Box();
public static final int height = (int) (Math.random() * 100);
public Box(){
area = width * height;
}
...
}
...
Example 1
では、width
の値が 10 であるため、開発者は box.area
が 10 の倍数のランダム整数であると予想します。しかし実際は、常にハードコーディングされた 0 の値です。コンパイル時定数で宣言された static final フィールドは最初に初期化され、順番に実行されます。これは、height
はコンパイル時定数ではないため box
の宣言の後に宣言され、コンストラクターはフィールド height
が初期化される前にコールされることを意味します。
...
class Foo{
public static final int f = Bar.b - 1;
...
}
...
class Bar{
public static final int b = Foo.f + 1;
...
}
This example is perhaps easier to identify, but would be dependent on which class is loaded first by the JVM. In this exampleFoo.f
could be either -1 or 0, andBar.b
could be either 0 or 1.
null
であるかを確認する前に、null
の可能性があるポインタを間接参照する場合です。チェック後間接参照のエラーが発生するのは、プログラムが null
に対して明示的チェックを実行したにも関わらず、null
であることが判明しているポインタを間接参照した場合です。この種のエラーの多くは、タイプミスかプログラマの不注意が原因です。格納後間接参照のエラーは、プログラムが明示的にポインタを null
に設定し、後でそのポインタを間接参照した場合に発生します。このエラーは通常、変数の宣言時にプログラマがその変数を null
に初期化したことが原因で発生します。foo
が null
であることを確認してから、それを誤って間接参照しています。foo
が if
ステートメントでチェックされたときに null
になっていると、null
間接参照 が発生し、これが NULL ポインター例外の原因となります。例 2: 次のコードでは、プログラマは変数
if (foo is null) {
foo.SetBar(val);
...
}
foo
は null
ではないと仮定しており、オブジェクトを間接参照することによってこの仮定を確認しています。しかし、その後プログラマが foo
と null
を比較したときに、この仮定は成り立たなくなります。foo
が if
ステートメントでチェックされたときに null
であるとすれば、間接参照されたときにも null
である可能性があり、これが NULL ポインタ例外の原因となる場合があります。間接参照が安全でないか、後で実行するチェックが不要であるかのいずれかです。例 3: 次のコードでは、プログラマは明示的に変数
foo.SetBar(val);
...
if (foo is not null) {
...
}
foo
を null
に設定しています。続いて、オブジェクトの null
値をチェックする前に foo
を間接参照しています。
Foo foo = null;
...
foo.SetBar(val);
...
}
null
であるかを確認する前に、null
の可能性があるポインタを間接参照する場合です。チェック後間接参照のエラーが発生するのは、プログラムが null
に対して明示的チェックを実行したにも関わらず、null
であることが判明しているポインタを間接参照した場合です。この種のエラーの多くは、タイプミスかプログラマの不注意が原因です。格納後間接参照のエラーは、プログラムが明示的にポインタを null
に設定し、後でそのポインタを間接参照した場合に発生します。このエラーは通常、変数の宣言時にプログラマがその変数を null
に初期化したことが原因で発生します。ptr
は NULL
ではないと仮定してします。この仮定は、プログラマがポインタを間接参照したときに明らかになります。その後プログラマが ptr
と NULL
を比較したときに、この仮定は成り立たなくなります。ptr
が if
ステートメントでチェックされたときに NULL
であるとすれば、間接参照されたときにも NULL
である可能性があり、これがセグメンテーション違反の原因となる場合があります。例 2: 次のコードでは、プログラマは変数
ptr->field = val;
...
if (ptr != NULL) {
...
}
ptr
が NULL
であることを確認してから、続いてそれを誤って間接参照しています。ptr
が if
ステートメントでチェックされたときに NULL
になっていると、null
Dereference が発生し、これがセグメンテーション違反の原因となります。例 3: 次のコードでは、プログラマが文字列
if (ptr == null) {
ptr->field = val;
...
}
'\0'
(実際は 0) または NULL
を忘れたため、NULL ポインタを間接参照し、セグメンテーション違反を引き起こしています。例 4: 次のコードでは、プログラマは明示的に変数
if (ptr == '\0') {
*ptr = val;
...
}
ptr
を NULL
に設定しています。続いて、オブジェクトの null
値をチェックする前に ptr
を間接参照しています。
*ptr = NULL;
...
ptr->field = val;
...
}
null
に対して明示的チェックを実行したにも関わらず、null
であることが判明しているオブジェクトを間接参照した場合です。この種のエラーの多くは、タイプミスかプログラマの不注意が原因です。foo
が null
であることを確認してから、続いてそれを誤って間接参照しています。foo
が if
ステートメントでチェックされたときに null
になっていると、null
Dereference が発生し、これが NULL ポインタ例外の原因となります。
if (foo == null) {
foo.setBar(val);
...
}
require
への呼び出しをバイパスできます。
function withdrawWinnings() {
require(uint32(msg.sender) == 0);
_sendWinnings();
}
function _sendWinnings() {
msg.sender.transfer(this.balance);
}
assert
を使用して、Lock
コントラクト インスタンスが特定の値 (msg.value
) であることを確認します。
contract Lock {
constructor (address owner, uint256 unlockTime) public payable {
...
}
}
contract Lockdrop {
...
function lock(...) {
uint256 eth = msg.value;
address owner = msg.sender;
uint256 unlockTime = unlockTimeForTerm(term);
Lock lockAddr = (new Lock).value(eth)(owner, unlockTime);
assert(address(lockAddr).balance == msg.value);
}
}
transfer()
や send()
など) に影響を与えたりする可能性があります。
interface ICallable {
function callMe() external;
}
contract HardcodedNotGood {
function callWithArgs() public {
callable.callMe{gas: 10000}();
}
}