001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.security; 017 018 019import java.util.Map; 020import java.util.WeakHashMap; 021import java.util.HashMap; 022 023/** 024 * URLHashMap は、セキュリティ強化の為の Hybs独自の暗号化クラスです。 025 * 026 * このクラスは、暗号化キーを受け取り、それに基づいて暗号化/復号化を行います。 027 * ここでの暗号化は、秘密キー方式でバイト文字列に変換されたものを、16進アスキー文字に 028 * 直して、扱っています。よって、暗号化/復号化共に、文字列として扱うことが可能です。 029 * 030 * @og.rev 5.2.2.0 (2010/11/01) 新規追加 031 * @og.group ライセンス管理 032 * 033 * @version 5.2.2.0 (2010/11/01) 034 * @author Kazuhiko Hasegawa 035 * @since JDK1.6, 036 */ 037public final class URLHashMap { 038 private static final int SIZE = 6000; 039 private static final Map<String,String> urlMap1 = new HashMap<String,String>( SIZE*4/3 ); // 現役世代1 040 private static Map<String,String> urlMap2 = new HashMap<String,String>( SIZE*4/3 ); // 現役世代2 041 private static final Map<String,String> urlMap3 = new WeakHashMap<String,String>( SIZE*4/3 ); // 旧世代 042 private static final Object lock = new Object(); 043 044 /** 045 * デフォルトコンストラクター 046 * これは、すべてstatic メソッドで構成されているクラスなので、直接インスタンスの生成を禁止します。 047 * 048 * @og.rev 5.3.0.0 (2010/12/01) 新規追加 049 */ 050 private URLHashMap() { 051 // 直接インスタンスの生成を禁止 052 } 053 054 /** 055 * URL をハッシュ化/暗号化して返します。 056 * 共通処理を簡易化するための、便利メソッドです。 057 * ここでのハッシュ化/暗号化は、URLのパラメータ(?以降の部分)のみ行います。 058 * また、ここで渡す文字列は、URLを含む文字列なので、href のキーワードを 059 * 手がかりに、? を探して、その部分のみ、変換します。 060 * href を含まない場合は、それ自体が URL と判断して、? を探します。 061 * ? が存在しないケースは、url をそのまま返します。 062 * 063 * URLのアドレスが、"/" から始まる場合は、自身のアドレスと判断し、ハッシュ処理を行います。 064 * そうでない場合(http:// や ../ の場合)は、暗号化処理を行います。 065 * 第2引数は、ハッシュ化/暗号化されたパラメータを指定するキーになります。(標準は、h_r) 066 * 処理を選択します。 067 * href を含まず、'?' だけを含む場合は、'?' 以降を暗号化します。 068 * 069 * ハッシュの場合、このキーを元に、設定値を内部キャッシュ(Map)に設定します。 070 * Map は、3世代持っており、内部キャッシュ(SIZE=6000)を超えると、2世代目に移行し、 071 * さらに、超えると、3世代目に移行します。3世代目は、WeakHashMap を利用している 072 * ため、場合によってはデータがなくなり、アクセス不能になっている可能性があります。 073 * 074 * @param url オリジナルのURL または、URL を含む文字列 075 * @param hkey パラメータのキーとして使用する文字 076 * @param extOnly 外部URLの場合のみ処理を実行する場合 true 077 * 078 * @return 変換されたURL を含む文字列 079 */ 080 public static String makeUrlChange( final String url , final String hkey , final boolean extOnly ) { 081 if( url == null || hkey == null ) { return null; } 082 // 外部のみ(extOnly=true)で、かつ、内部URLの形式の場合、引数そのままを返します。 083 if( extOnly && url.indexOf( "href=\"/" ) >= 0 ) { return url; } 084 085 String rtnUrl = url; 086 087 int idx1 = url.indexOf( "href=\"" ); 088 int idx2 = url.indexOf( '?', idx1 ); // href・・・ がない時(idx1 == -1)でも正常に動作する。 089 if( idx2 >= 0 ) { 090 String url1 = url.substring( 0,idx2+1 ); // 最初から '?' まで(?を含む) 091 int idx3 = url.indexOf( "\"",idx2+1 ); 092 if( idx3 >= 0 ) { 093 String url2 = url.substring( idx2+1,idx3 ); // 純粋なパラメータ部分 094 String url3 = url.substring( idx3 ); // ダブルクオート(含む)以降 095 // href="/ かどうか。文字列の有効長があるかどうかを先にチェックしている。 096 if( idx1 >= 0 && url.length() > idx1+7 && url.charAt( idx1+7 ) == '/' ) { 097 url2 = makeHashKey( url2 ); 098 } 099 else { 100 url2 = makeEncrypt( url2 ); 101 } 102 rtnUrl = url1 + hkey + "=" + url2 + url3 ; 103 } 104 // '?' はあるが、最後のダブルクオートがない場合は、'?' から後ろすべてを暗号化する。 105 else { 106 String url2 = url.substring( idx2+1 ); // ?以降の部分 107 rtnUrl = url1 + hkey + "=" + makeEncrypt( url2 ) ; 108 } 109 } 110 111 return rtnUrl; 112 } 113 114 /** 115 * 引数の設定値をハッシュ化したときの値(=ハッシュキー)を作成します。 116 * 内部的に、このハッシュキーを元に、設定値を内部キャッシュ(Map)に設定します。 117 * このMapは、WeakHashMap を利用しているため、場合によってはデータがなくなり、 118 * アクセス不能になっている可能性があります。 119 * 120 * @param val オリジナルの設定値 121 * 122 * @return ハッシュキー 123 */ 124 public static String makeHashKey( final String val ) { 125 if( val == null ) { return ""; } 126 127 // 必殺技:最後に "X" を付けることで、ハッシュ処理されたことを示す。 128 String key = HybsCryptography.getMD5( val ) + "X"; 129 synchronized( lock ) { 130 urlMap1.put( key,val ); 131 } 132 return key; 133 } 134 135 /** 136 * 引数の設定値を暗号化したときの値を作成します。 137 * 暗号化なので、ハッシュ化の時の用に、内部キャッシュ(Map)に設定しません。 138 * 処理時間等を考慮すると、外部URLの暗号化や、長期にわたるURL(一旦、システムの 139 * 外部にURLを渡す:例えば、メールでリンク先を送信するなど)の作成に使用します。 140 * 141 * @param val オリジナルの設定値 142 * 143 * @return 暗号化キー 144 */ 145 public static String makeEncrypt( final String val ) { 146 if( val == null ) { return ""; } 147 148 // 必殺技:最後に "Y" を付けることで、暗号化処理されたことを示す。 149 HybsCryptography crypt = new HybsCryptography(); 150 return crypt.encrypt( val ) + "Y"; 151 } 152 153 /** 154 * 指定のキーに対応した設定値を取り出します。 155 * ここでは、ハッシュ化 または 暗号化されているキーに対して、 156 * ハッシュキーであれば、関連付けられた設定値を取り出し、暗号化キーで 157 * あれば、復号化処理を行います。 158 * 159 * @param key ハッシュ化/暗号化されたキー 160 * 161 * @return オリジナルの設定値 162 */ 163 public static String getValue( final String key ) { 164 if( key == null || key.isEmpty() ) { return null; } 165 166 String rtn = null; 167 168 char ch = key.charAt( key.length()-1 ); 169 if( ch == 'X' ) { 170 synchronized( lock ) { 171 rtn = urlMap1.get( key ); 172 if( rtn == null ) { rtn = urlMap2.get( key ); } 173 if( rtn == null ) { rtn = urlMap3.get( key ); } 174 175 // ハッシュを作成するより取得する方が頻度が少ない。 176 if( urlMap1.size() > SIZE ) { 177 urlMap3.putAll( urlMap2 ); 178 urlMap2 = new HashMap<String,String>( urlMap1 ); 179 urlMap1.clear(); 180 } 181 } 182 } 183 else if( ch == 'Y' ) { 184 HybsCryptography crypt = new HybsCryptography(); 185 rtn = crypt.decrypt( key.substring( 0,key.length()-1 ) ); 186 } 187 188 return rtn ; 189 } 190}