WEB安全実戦(一)SQL盲注

12620 ワード

前言
長い間書いたことがないので、書きたくないのではなく、ずっと心を落ち着かせずに何かを書いているだけです.もちろん、こんなに長い間引きずっていても、何か書くべきだ.最近安全面については、菜鳥としても、勉強の目的で、最近触れた安全面について話しましょう.
背景
背景に言及した以上、私たちは簡単に持ってきて、最近インターネット上で各種の驚くべき事件、各種のドア、各種の写真が爆発して、結局、すべてネットの安全が出した問題で、あるのはネットが他の人に監視されて、広範な大衆の生活の仕事はすべて人の目の下にあって、一挙手一投足はすべて人の“法眼”から逃れられません;また、一部の業者のserverが黒くなったり、username、passwordが盗まれたり、クレジットカードが盗まれたり、プライベートファイルが漏れたりしています.これらはすべて安全に問題が発生した.もちろん、アップルのような大きな会社では、このような事件が発生します.普通の小さな会社は言うまでもありません.
に質問
SQL盲注、この言葉はあまり知られていないと思います.もし本当に知らなかったら、「SQL注入」はきっと聞いたことがあります.この二つの言葉は何か関係があるようで、双子のようですか.そう、SQL盲注はWebシステムのセキュリティホールであり、比較的深刻なものであり、SQL注入の一つの方法である.すなわち、SQL注入には非常に多くの方法があり、SQLブラインド注入はその一つである.
セキュリティ・レベルでは、SQLブラインド・ノートは非常に脅威的なセキュリティ・ホールであり、サービス・プロバイダのserverデータベースに侵入し、ユーザー・データを盗み取り、改ざんし、削除することができます.もちろん、通常の状況では、これらは発生に同意しません.システムがオンラインになる前に、これらは厳格に検出され、データベース内のデータも指向性のない暗号化されており、ユーザーデータが露出しません.
技術描写叙述
IBMのAppScanを採用して、システムに対してテストを行って、初期の開発の中で、非常に多くの規範化されていないコードを採用したため、今回のテストは“大豊作”と言えるので、サイトの安全面の抜け穴は間違いなく暴露して、安全テストの報告の中で、最も深刻な抜け穴はSQLの盲注ではありません.
解決策
SQL盲注の危害はみんなもすべて明らかになって、それではどのようにこのような情況の発生を防止しますか?簡単に言えば、要求をフィルタリングし、パラメータを検証し、不正な文字をブロック置換し、ユーザーが入力した危険な文字を整理し、sqlがデータベースで正しくコンパイルされ、実行されることを保証することです.これが解決の簡単な考え方です.ただ、今日私が言いたいのはこれではなく、巨人の肩に問題を見つけて、この問題を解決することです.
MyBatisは、かなり使いやすい持続的なフレームワークで、それがあった後、私たちは非常に多くの時間を節約し、非常に多くの繰り返しの仕事をしました.同じ時、フレームワークの運用においても、いくつかの安全問題が存在していることを認識しなければならない.もちろん、フレームワークの中には非常に良い解決方法が与えられているものもあるが、私たち自身が解決しなければならないものもある.例えば、このSQL盲注の問題は、MyBatisがmapperで非常に良い解決方法を提供しています.xmlファイルでは#{name}を使用してプレースホルダを提供し、sqlがデータベースでコンパイルされると、これらのプレースホルダをユーザーが入力した正しいパラメータ値に置き換え、一部の問題を回避します.
コード例えば以下
<span style="font-family:Comic Sans MS;font-size:12px;"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.dao.TAcntMapper">
  <resultMap id="BaseResultMap" type="com.test.entity.TAcnt">
     <id column="SYS_ID" jdbcType="DECIMAL" property="sysId" />
   	 <result column="OBJ_ID" jdbcType="VARCHAR" property="objId" />
   	 <result column="OBJ_NAME" jdbcType="VARCHAR" property="objName" />
   	 <result column="OBJ_DESCRIPTION" jdbcType="VARCHAR" property="objDescription" />
   	 <result column="CREATOR" jdbcType="VARCHAR" property="creator" />
   	 <result column="CREATE_TIME" jdbcType="TIMESTAMP" property="createTime" />
   	 <result column="UPDATE_OPERATOR" jdbcType="VARCHAR" property="updateOperator" />
   	 <result column="UPDATE_TIME" jdbcType="TIMESTAMP" property="updateTime" />
   	 <result column="CLIENT_CHK_FLAG" jdbcType="DECIMAL" property="clientChkFlag" />
   	 <result column="CELL_PHONE" jdbcType="VARCHAR" property="cellPhone" />
   	 <result column="REG_EMAIL" jdbcType="VARCHAR" property="regEmail" />
   	 <result column="GENDER" jdbcType="DECIMAL" property="gender" />
   	 <result column="QQ_NO" jdbcType="VARCHAR" property="qqNo" />
   	 <result column="WEB_URL" jdbcType="VARCHAR" property="webUrl" />
   </resultMap>
 

  <sql id="Example_Where_Clause">
    <where>
      <foreach collection="oredCriteria" item="criteria" separator="or">
        <if test="criteria.valid">
          <trim prefix="(" prefixOverrides="and" suffix=")">
            <foreach collection="criteria.criteria" item="criterion">
              <choose>
                <when test="criterion.noValue">
                  and ${criterion.condition}
                </when>
                <when test="criterion.singleValue">
                  and ${criterion.condition} #{criterion.value}
                </when>
                <when test="criterion.betweenValue">
                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
                </when>
                <when test="criterion.listValue">
                  and ${criterion.condition}
                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
                    #{listItem}
                  </foreach>
                </when>
              </choose>
            </foreach>
          </trim>
        </if>
      </foreach>
    </where>
  </sql>
  <sql id="Update_By_Example_Where_Clause">
    <where>
      <foreach collection="example.oredCriteria" item="criteria" separator="or">
        <if test="criteria.valid">
          <trim prefix="(" prefixOverrides="and" suffix=")">
            <foreach collection="criteria.criteria" item="criterion">
              <choose>
                <when test="criterion.noValue">
                  and ${criterion.condition}
                </when>
                <when test="criterion.singleValue">
                  and ${criterion.condition} #{criterion.value}
                </when>
                <when test="criterion.betweenValue">
                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
                </when>
                <when test="criterion.listValue">
                  and ${criterion.condition}
                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
                    #{listItem}
                  </foreach>
                </when>
              </choose>
            </foreach>
          </trim>
        </if>
      </foreach>
    </where>
  </sql>
  <sql id="Base_Column_List">
          SYS_ID     , OBJ_ID     , OBJ_NAME     , OBJ_DESCRIPTION     , CREATOR     , CREATE_TIME     , UPDATE_OPERATOR     , UPDATE_TIME     , CLIENT_CHK_FLAG     , CELL_PHONE     , REG_EMAIL     , GENDER     , QQ_NO     , WEB_URL  </sql>

  <sql id="From_join">
  from   	 T_ACNT 
  </sql>
  
  <select id="selectByExample" parameterType="com.test.entity.TAcntCriteria" resultMap="BaseResultMap">
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    <include refid="From_join" /> 
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
  </select>
  
  <select id="selectByPrimaryKey" parameterType="BigDecimal" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    <include refid="From_join" /> 
    where SYS_ID = #{sysId,jdbcType=DECIMAL}
  </select>
  
  <delete id="deleteByExample" parameterType="com.test.entity.TAcntCriteria">

    delete from T_ACNT
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
  </delete>
  
  <insert id="insert" parameterType="com.test.entity.TAcnt">
          insert into T_ACNT ( OBJ_ID     , OBJ_NAME     , OBJ_DESCRIPTION     , CREATOR     , CREATE_TIME     , UPDATE_OPERATOR     , UPDATE_TIME     , CLIENT_CHK_FLAG     , CELL_PHONE     , REG_EMAIL     , GENDER     , QQ_NO     , WEB_URL )
    values (        #{objId,jdbcType=VARCHAR}      , #{objName,jdbcType=VARCHAR}      , #{objDescription,jdbcType=VARCHAR}      , #{creator,jdbcType=VARCHAR}      , #{createTime,jdbcType=TIMESTAMP}      , #{updateOperator,jdbcType=VARCHAR}      , #{updateTime,jdbcType=TIMESTAMP}      , #{clientChkFlag,jdbcType=DECIMAL}      , #{cellPhone,jdbcType=VARCHAR}      , #{regEmail,jdbcType=VARCHAR}      , #{gender,jdbcType=DECIMAL}      , #{qqNo,jdbcType=VARCHAR}      , #{webUrl,jdbcType=VARCHAR}  )
  </insert>  
  
  
  <select id="countByExample" parameterType="com.test.entity.TAcntCriteria" resultType="java.lang.Integer">
    select count(*) 
    <include refid="From_join" /> 
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
  </select>
  
  <update id="updateByExample" parameterType="map">
    update T_ACNT
    set				OBJ_ID = #{record.objId,jdbcType=VARCHAR} 
               , OBJ_NAME = #{record.objName,jdbcType=VARCHAR} 
               , OBJ_DESCRIPTION = #{record.objDescription,jdbcType=VARCHAR} 
               , CREATOR = #{record.creator,jdbcType=VARCHAR} 
               , CREATE_TIME = #{record.createTime,jdbcType=TIMESTAMP} 
               , UPDATE_OPERATOR = #{record.updateOperator,jdbcType=VARCHAR} 
               , UPDATE_TIME = #{record.updateTime,jdbcType=TIMESTAMP} 
               , CLIENT_CHK_FLAG = #{record.clientChkFlag,jdbcType=DECIMAL} 
               , CELL_PHONE = #{record.cellPhone,jdbcType=VARCHAR} 
               , REG_EMAIL = #{record.regEmail,jdbcType=VARCHAR} 
               , GENDER = #{record.gender,jdbcType=DECIMAL} 
               , QQ_NO = #{record.qqNo,jdbcType=VARCHAR} 
               , WEB_URL = #{record.webUrl,jdbcType=VARCHAR} 
            <if test="_parameter != null">
      <include refid="Update_By_Example_Where_Clause" />
    </if>
  </update>
  
  <update id="updateByPrimaryKeySelective" parameterType="com.test.entity.TAcnt">
    update T_ACNT
    <set>
      <if test="objId != null">
        OBJ_ID = #{objId,jdbcType=VARCHAR},
      </if>
      <if test="objName != null">
        OBJ_NAME = #{objName,jdbcType=VARCHAR},
      </if>
      <if test="objDescription != null">
        OBJ_DESCRIPTION = #{objDescription,jdbcType=VARCHAR},
      </if>
      <if test="creator != null">
        CREATOR = #{creator,jdbcType=VARCHAR},
      </if>
      <if test="createTime != null">
        CREATE_TIME = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updateOperator != null">
        UPDATE_OPERATOR = #{updateOperator,jdbcType=VARCHAR},
      </if>
      <if test="updateTime != null">
        UPDATE_TIME = #{updateTime,jdbcType=TIMESTAMP},
      </if>
      <if test="clientChkFlag != null">
        CLIENT_CHK_FLAG = #{clientChkFlag,jdbcType=DECIMAL},
      </if>
      <if test="cellPhone != null">
        CELL_PHONE = #{cellPhone,jdbcType=VARCHAR},
      </if>
      <if test="regEmail != null">
        REG_EMAIL = #{regEmail,jdbcType=VARCHAR},
      </if>
      <if test="gender != null">
        GENDER = #{gender,jdbcType=DECIMAL},
      </if>
      <if test="qqNo != null">
        QQ_NO = #{qqNo,jdbcType=VARCHAR},
      </if>
      <if test="webUrl != null">
        WEB_URL = #{webUrl,jdbcType=VARCHAR},
      </if>
    </set>
    where SYS_ID = #{sysId,jdbcType=DECIMAL}
  </update>
</mapper></span>

もちろん、これは最初のステップにすぎません.SQLの盲注を徹底的に防止するシステムを書きたいとします.では、ユーザーが発行したリクエストをフィルタリングする必要があります.また、リクエストのパラメータ値も含まれます.いくつかの危険文字が含まれている可能性があります.これらの危険文字は、フィルタリングして処理する必要がある問題です.危急文字の解決については、XSS、CSRFなど、非常に多くの脆弱性に関連しているため、後で詳しく説明します.
終わりの言葉
ことわざにもあるように、安全は虎より強い!安全は些細なことではない!インターネットでは、これらも同じです.安全に触れ始めたばかりの私は、安全を深く研究し始めたばかりの私が、この方面の養分を汲み取り、テストされた安全の抜け穴を通じて、潜在的な危機を少しずつ解決していると言っているかもしれません.これはまだ始まりにすぎません.もしかすると、まだ長い道のりがあるかもしれません.みんなで頑張りましょう.もちろん、もし何か新しい感じがあったら、私もみんなと一緒に分かち合い、一緒に進歩することを書きます.