Cookie の保護に関するJeff のブログ投稿: HttpOnlyを読んだ後。Web アプリケーションに HttpOnly Cookie を実装したいと考えています。
セッションに http のみの Cookie を使用するように tomcat に指示するにはどうすればよいですか?
httpOnly は、Tomcat 6.0.19 および Tomcat 5.5.28 でサポートされています。
バグ 44382の変更ログエントリを参照してください。
バグ44382の最後のコメントには、「これは 5.5.x に適用されており、5.5.28 以降に含まれる予定です」と記載されています。ただし、5.5.28 がリリースされたようには見えません。
httpOnly 機能は、conf/context.xml内のすべての webapps に対して有効にすることができます:
<Context useHttpOnly="true">
...
</Context>
私の解釈では、 conf/server.xmlの目的のContextエントリに(上記と同じ方法で) 設定することにより、個々のコンテキストに対しても機能するということです。
更新: ここにある JSESSIONID は、古いコンテナー専用です。Tomcat 6.0.19未満またはTomcat 5.5.28未満、または構成オプションとしてHttpOnly JSESSIONID Cookieをサポートしない別のコンテナを使用していない限り、jtの現在受け入れられている回答を使用してください。
アプリで Cookie を設定するときは、
response.setHeader( "Set-Cookie", "name=value; HttpOnly");
ただし、多くの Web アプリケーションでは、最も重要な Cookie はセッション識別子であり、コンテナによって JSESSIONID Cookie として自動的に設定されます。
この Cookie のみを使用する場合は、ServletFilter を記述して、途中で Cookie を再設定し、JSESSIONID を HttpOnly に強制することができます。http://keepitlocked.net/archive/2007/11/05/java-and-httponly.aspx http://alexsmolen.com/blog/?p=16のページでは、フィルタに次を追加することを提案しています。
if (response.containsHeader( "SET-COOKIE" )) {
String sessionid = request.getSession().getId();
response.setHeader( "SET-COOKIE", "JSESSIONID=" + sessionid
+ ";Path=/<whatever>; Secure; HttpOnly" );
}
ただし、これによりすべての Cookie が上書きされ、ここで指定した内容のみがこのフィルターに設定されることに注意してください。
JSESSIONID Cookie に追加の Cookie を使用する場合は、このコードを拡張してフィルター内のすべての Cookie を設定する必要があります。これは、複数の Cookie の場合には優れた解決策ではありませんが、JSESSIONID のみの設定ではおそらく受け入れられるクイックフィックスです。
コードが時間の経過とともに進化するにつれて、このフィルターを忘れてコード内の別の場所に別の Cookie を設定しようとすると、厄介な隠れたバグが待っていることに注意してください。もちろん、固まりません。
しかし、これは本当にハックです。Tomcat を使用してコンパイルできる場合は、Shabaz の HttpOnly サポートを Tomcat にパッチするための優れた提案を参照してください。
https-sessions の「;secure」Cookie フラグを上書きしないように注意してください。このフラグは、ブラウザが暗号化されていない http 接続を介して Cookie を送信するのを防ぎ、基本的に正当なリクエストに https を使用することを無意味にします。
private void rewriteCookieToHeader(HttpServletRequest request, HttpServletResponse response) {
if (response.containsHeader("SET-COOKIE")) {
String sessionid = request.getSession().getId();
String contextPath = request.getContextPath();
String secure = "";
if (request.isSecure()) {
secure = "; Secure";
}
response.setHeader("SET-COOKIE", "JSESSIONID=" + sessionid
+ "; Path=" + contextPath + "; HttpOnly" + secure);
}
}
Web サーバーが Servet 3.0 仕様 (Tomcat 7.0+ など) をサポートしている場合は、以下を次のように使用できますweb.xml
。
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>
ドキュメントで述べたように:
HttpOnly : この Web アプリケーションによって作成されたセッション追跡 Cookie を HttpOnly としてマークするかどうかを指定します
Secure : 対応するセッションを開始したリクエストが HTTPS ではなくプレーン HTTP を使用している場合でも、この Web アプリケーションによって作成されたセッション追跡 Cookie をセキュアとしてマークするかどうかを指定します。
セッション Cookie については、Tomcat ではまだサポートされていないようです。HTTPOnly セッション Cookie パラメータのサポートを追加する必要があるというバグ レポートを参照してください。現在のところ、やや複雑な回避策がここにあります。基本的には、Tomcat に手動でパッチを適用することになります。現時点では、それを行う簡単な方法を実際に見つけることはできません。
回避策を要約すると、5.5 のソースをダウンロードし、次の場所でソースを変更します。
org.apache.catalina.connector.Request.java
//this is what needs to be changed
//response.addCookieInternal(cookie);
//this is whats new
response.addCookieInternal(cookie, true);
}
org.apache.catalina.connectorResponse.addCookieInternal
public void addCookieInternal(final Cookie cookie) {
addCookieInternal(cookie, false);
}
public void addCookieInternal(final Cookie cookie, boolean HTTPOnly) {
if (isCommitted())
return;
final StringBuffer sb = new StringBuffer();
//web application code can receive a IllegalArgumentException
//from the appendCookieValue invokation
if (SecurityUtil.isPackageProtectionEnabled()) {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run(){
ServerCookie.appendCookieValue
(sb, cookie.getVersion(), cookie.getName(),
cookie.getValue(), cookie.getPath(),
cookie.getDomain(), cookie.getComment(),
cookie.getMaxAge(), cookie.getSecure());
return null;
}
});
} else {
ServerCookie.appendCookieValue
(sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
cookie.getPath(), cookie.getDomain(), cookie.getComment(),
cookie.getMaxAge(), cookie.getSecure());
}
//of course, we really need to modify ServerCookie
//but this is the general idea
if (HTTPOnly) {
sb.append("; HttpOnly");
}
//if we reached here, no exception, cookie is valid
// the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
// RFC2965 is not supported by browsers and the Servlet spec
// asks for 2109.
addHeader("Set-Cookie", sb.toString());
cookies.add(cookie);
}
明示的に設定しているCookieについては、 ApacheShiroが提供するSimpleCookieを使用するように切り替えました。これはjavax.servlet.http.Cookieから継承しないため、すべてを正しく機能させるにはもう少し手間がかかりますが、プロパティセットHttpOnlyを提供し、サーブレット2.5で機能します。
応答にCookieを設定するには、実行するのではなく、実行response.addCookie(cookie)
する必要がありますcookie.saveTo(request, response)
。
また、HttpOnly をオンにすると、jvm へのステートフル アクセスを必要とするアプレットが壊れることにも注意してください。
アプレットの http リクエストは jsessionid Cookie を使用せず、別の tomcat に割り当てられる可能性があります。
OWASPで見つけた
<session-config>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
</session-config>
これは、「構成内の httponlycookies」セキュリティ問題の修正でもあります
Tomcat6 では、HTTP リスナー クラスから条件付きで有効にすることができます。
public void contextInitialized(ServletContextEvent event) {
if (Boolean.getBoolean("HTTP_ONLY_SESSION")) HttpOnlyConfig.enable(event);
}
このクラスの使用
import java.lang.reflect.Field;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import org.apache.catalina.core.StandardContext;
public class HttpOnlyConfig
{
public static void enable(ServletContextEvent event)
{
ServletContext servletContext = event.getServletContext();
Field f;
try
{ // WARNING TOMCAT6 SPECIFIC!!
f = servletContext.getClass().getDeclaredField("context");
f.setAccessible(true);
org.apache.catalina.core.ApplicationContext ac = (org.apache.catalina.core.ApplicationContext) f.get(servletContext);
f = ac.getClass().getDeclaredField("context");
f.setAccessible(true);
org.apache.catalina.core.StandardContext sc = (StandardContext) f.get(ac);
sc.setUseHttpOnly(true);
}
catch (Exception e)
{
System.err.print("HttpOnlyConfig cant enable");
e.printStackTrace();
}
}
}