findone関数に注意してください


こんにちは、私の最後のポスト以来、私は情報セキュリティ産業に移動し、研究/近代的なアプリケーションの脆弱性について多くを調査を開始した.
このポストでは、我々はどのようにNOSQLの注射に対してWebアプリケーションを保護する方法を見つける
に従ってOWASP Top 10 - 2017 , 昨年の最も頻繁な脆弱性はA1:2017-Injection , 脆弱性のあるシステムの特定の時点で悪意あるコードの注入を参照してください、最も既知の注入は、URLを通じてSQLインジェクションです、フォームを通じて、我々は被害者のデータベースに悪意のあるクエリを送信することができます.
最近では、ユーザを認証するためにAPIを持っているシステムを見つけるのが一般的であり、この情報を格納するために非リレーショナルデータベースを使用しますMongo .
以下の例では、NeDB Mongoとよく似た構文を持つ銀行.
コントローラ
exports.login = async (req, reply) => {
    try {
        let { user, pass } = req.body

        let result = await findOne({user, pass})

        return reply.code(200).send(result)
    } catch (e) {
        return reply.code(500).send({ success: false, result: 'user/pass not found' })
    }
}
データベース.フィンド
async function findOne(query) {
    return new Promise((resolve, reject) => {
        db.findOne(query, (err, result) => {
            if (err) return reject(err)

            resolve({ success: true, result })
        })
    })
}

私たちがfindoneに渡されたオブジェクトが有効なオブジェクトであったので、ログインは作られました、すなわち、ユーザとパスはデータベースに実際に存在する値を持ちます.
この投稿の冒頭でSQL注射についてコメントしましたが、NoSQL注射を聞いたことがありますか?ない?では、次の関数を見てください.

db.findOne(query, (err, result) => {
    if (err) return reject(err)

    resolve({ success: true, result })
})
基本的に、この関数が何をするのかは、ユーザが& amp ;& passに渡した値のレコードがあるかどうかを知るためのデータベースのチェックです.
これは、少なくとも有効なユーザをパスし、パスの代わりにtrueを返す別の検証を通知すると、関数が動作するとは思わないでしょうか?
MongoとNEDbの両方とも、データベース内のクエリで使用できるフィルタを持っています.例えば、$ gt、それはリレーショナル演算子">の等価です.パスワードの代わりにこのフィルタを使用して質問をしましょう.

すなわち、ユーザが「WUBBA」と記録しているかどうかを尋ね、パスの値が“None”より大きいことを問うデータベースに問い合わせを行いました.その名前のユーザがあれば、パスワードは“None”より大きくなります.
我々が同じ物を通過するならば{"$ gt": ""} ユーザーとパスでは、銀行はそれが最初のレコードを返す!
これはFindone関数が危険であることを示しています.もし我々がそれに渡す値の処理を作成しない場合は、この場合、情報がオブジェクトではないかどうかを検証できます.
修正するには、以下の関数を使用できます
コントローラ
exports.loginProtected = async (req, reply) => {
    try {
        let { user, pass } = req.body
        await isObject({ user, pass })

        let result = await findOne({user, pass})

        return reply.code(200).send(result)
    } catch (e) {
        return reply.code(500).send({ success: false, result: 'user/pass not found' })
    }
}
オブジェクト

async function isObject(params) {
    return new Promise((resolve, reject) => {
        Object.keys(params).forEach((v, i) => {
            if (typeof params[v] === 'object') return reject(false)
        })
        resolve(true)
    })
}
このケースはNeDB しかし、銀行も使用してシミュレートされたMongo and Sails/Waterline , あなたが他の銀行で見つけるならば、誰かを助けるために、ここでコメントしてください😉
ギタブプロジェクトhttps://github.com/nulldreams/nosql-pentest