XSS 跨站腳本攻擊:
Cross-site scripting(簡稱xss)跨站腳本。
一種網站的安全漏洞的攻擊,代碼注入攻擊的一種。XSS攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令代碼到網頁,使用戶加載並執行攻擊者惡意制造的網頁程序。這些惡意網頁程序通常是JavaScript,但實際上也可以包括Java,VBScript,ActiveX,Flash或者甚至是普通的HTML。攻擊成功后,攻擊者可能得到更高的權限(如執行一些操作)、私密網頁內容、會話和cookie等各種內容。
例子:
<script>
$.ajax({
url: $(location).attr('href') + "/comments",
method: "POST",
data: { comment : { content: "啊哈哈哈~你看看你! (σ゚∀゚)σ゚∀゚)σ゚∀゚)σ" } },
dataType: "JSON"
})
</script>
url: window.location.href + "/comments" 生成"http://localhost:3000/events/1/comments"
這主要是因為在views/events/show.html.erb中:
<% raw comment.content%>這行代碼中有raw()方法
這個方法會輸出所有字符,不會放過tag標簽。去掉raw()后,content兩邊加上引號變為字符串。
但這樣就不能插入img等有用的tag了。這時可以使用sanitize()方法。
str.html_safe方法
跨站請求偽造 Cross-site request forgery
也稱為one-click attack, 簡稱CSRF或XSRF.
是攻擊者通過一些技術手段欺騙用戶的瀏覽器去訪問一個自己曾經認證過的網站並執行一些操作(如發郵件,發消息,甚至財產操作如轉賬和購買商品)。由於瀏覽器曾經認證過,所以被訪問的網站會認為是真正的用戶操作而去執行。這利用了web中用戶身份驗證的一個漏洞:簡單的身份驗證只能保證請求發自某個用戶的瀏覽器,卻不能保證請求本身是用戶自願發出的。
例子:
在任意位置插入惡意代碼:如
<img src="/events/92/comments/522/highlight"> 偽裝成是用戶發送的請求。
防御方法:添加校驗token
token是在非get請求中使用。因此需要看代碼中關於修改數據庫的請求,是否是用了get請求,如果是必須改成非get請求。這樣img就不能攻擊了。
Rails默認帶了protect_from_forgery with: :exception ,⚠️5.2隱藏了這行code。
1. 這樣在 Rails 產生的表單form中,就有帶這個參數 authenticity_token。
表單的提交就會進行token驗證
<form class="new_comment" id="new_comment" action="/events/2/comments" accept-charset="UTF-8" method="post">
<input name="utf8" type="hidden" value="✓">
<input type="hidden" name="authenticity_token" value="fMv3c2b177kqsy/LuDIARp+RaQWJtBHwfQkbEV8j5wqNVFFSBqvcotvkeV07hiQpWsQY1RIEdpVMvE4vysEHiA==">
<div class="form-group">
<label for="comment_content">Content</label>
<textarea class="form-control" name="comment[content]" id="comment_content"></textarea>
</div>
<div class="form-group">
<input type="submit" name="commit" value="Comment" class="btn btn-primary" data-disable-with="Comment">
</div>
</form>
2. 如果是Rails.ajax中的請求:就會抓 meta 中的 csrf-token
參數附加到請求中。和form中的value是一樣的。
Rails.ajax()方法,會抓取csrfToken。校驗token。
在csrf.coffee中:
csrfToken = Rails.csrfToken = ->
meta = document.querySelector('meta[name=csrf-token]')
meta and meta.content
得到:
<meta name="csrf-token" content="fMv3c2b177kqsy/LuDIARp+RaQWJtBHwfQkbEV8j5wqNVFFSBqvcotvkeV07hiQpWsQY1RIEdpVMvE4vysEHiA==">
這樣,黑客在其他網站上挖的坑因為沒有這個authenticity_token或csrf-token(兩者值一樣),他發送的請求就會被擋住。
SQL Injection 數據庫注入攻擊structured query language.
@comments = @comments.where( "comments.content LIKE '%#{params[:keyword]}%'")
轉換:
SELECT "comments".* FROM "comments" WHERE "comments"."event_id" = ? AND (comments.content LIKE '%這是搜尋關鍵字%') [["event_id", 95]]
如果收到的參數是
sorry'); DELETE * FROM comments; --
轉換為sql就成了3句代碼:
SELECT "comments".* FROM "comments" WHERE "comments"."event_id" = ? AND (comments.content LIKE '%sorry'); DELETE * FROM comments; --%') [["event_id", 95]]
第一句是查詢,第二句就成了刪除了!!, --后面代表了注釋。
問題的原因:是查詢語法使用string造成的。
這樣單引號,\backslash就會起到了它的作用。
可以使用quote_string(s)方法來給一個string逸出單引號和反斜杠。
keyword = ActiveRecord::Base::connection.quote_string( params[:keyword] )
又因為查詢語法where經常用到,所以增加了簡單的寫法, 自動逸出:
@comments = @comments.where( "comments.content LIKE ?", "%#{params[:keyword]}%")
@registrations = Registraion.where( :status => params[:status] ) # Hash 寫法,這是安全的
@registrations = Registraion.where( "status = ?", params[:status] ) # Array 寫法,這是安全的
但order等語法,沒做自動逸出: (點擊查看所有需要注意的sql語法)
可以使用白名單:
app/views/events/show.html.erb
<p>
<%= link_to "新留言在上", event_path(@event, :sort => "id DESC") %>
<%= link_to "舊留言在上", event_path(@event, :sort => "id ASC") %>
</p>
app/controllers/events_controller.rb
- if params[:sort] # 本來這樣有漏洞,你太相信用戶傳進來的參數了
+ if params[:sort] && ["id DESC", "id ASC"].include?(params[:sort]) # 只有白名單內的參數可以用 @comments = @comments.order(params[:sort]) end
Delete_all和 Destroy_all
都要小心使用!。它們都接受和find()方法相同的條件參數。參數可以是string, array, hash。但Strings不會被脫逸, 所以安全的寫法是只用array, hash做參數。
Destroy_all因為會實例化記錄並調用destroy方法並調用callbacks,相對比delete_all安全。
params[:admin] = "') OR 1=1--'"
User.destroy_all(["id = ? AND admin = '#{params[:admin]}", params[:id]])
生成:SELECT "users".* FROM "users" WHERE (id = NULL AND admin = '') OR 1=1--')
這會刪除所有users。
Exists?()方法。
他用來判斷一條記錄是否存在。參數一般是一個主鍵。如果參數是array或hash,它被當成一個條件option。
為了安全,參數最好是一個integer或string。
Group()方法
他可以接受任意的SQL string。因此
params[:group] = "name UNION SELECT * FROM users"
User.where(:admin => false).group(params[:group])
生成 :
SELECT "users".* FROM "users" WHERE "users"."admin" = ? GROUP BY name UNION SELECT * FROM users
因為union了另外一條sql,因此返回所有的users。
Having()方法
容易遭到Sql injection攻擊,因為它一般在一條rails查詢語句的最后。
Joins方法
它可以接收一個關聯數組或直接的SQl string。因此也可能會遭到注入攻擊。
Select(*fields)方法
因為select子句一般在一個查詢的開頭,所以幾乎任何sql都可以注入並生效。
params[:column] = "* FROM users WHERE admin = 't' ;"
User.select(params[:column])
Query
Result:返回的是一個關系對象。
select有2種用法:
- 修改select聲明,檢索指定的fields。返回一個對象關系a relation object。可以在后面添加其他查詢方法。
- 接受一個塊{}, 類似Array#select。從數據庫中得到一個array對象的集合。
Pluck(*column_names)
從一個table中選擇指定的column。接受任何Sql。所以容易收到注入攻擊。返回一個array對象集合。
大量賦值(Mass Assignment)的漏洞
rails5增加了strong parameters
params.require(:XXX).permit(:column_name, ...)限定了可以傳入什么參數。
但也要謹慎使用。關鍵的列,即使隱藏,也可以通過url修改。所以應該留意一個column是否是要傳入的,如果不是,就別加入白名單。
如果hacker在chrome瀏覽器的inspect上修改參數,
log上會顯示:Unpermitted parameter: role
破解加密 Cookie-based Session(太復雜,只了解了一下)
密匙不能外泄,如果外泄,必須馬上更換。rails可以更換session的存儲方法。
Module: Base64 (defined in lib/base64.rb)
這個模塊提供了binary data的編碼和解碼。
require "base64" enc = Base64.encode64('Send reinforcements') # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n" plain = Base64.decode64(enc) # -> "Send reinforcements"
這個模塊提供了生成密碼的算法。它包裹了OpenSSL library.
DoS 拒絕服務攻擊
denial of service attack, distributed denial of service attack分布拒絕服務攻擊。
對自己的網站叫做壓力測試
安裝wrk:(https://github.com/wg/wrk)
執行 brew install wrk
執行 wrk -t12 -c400 -d30s http://localhost:3000/products
t:thread
c: connection, HTTP連接的總數,每個thread處理 connections/threads個連接。
d: duration of the test 例子: 2s, 2m, 2h
如何防御ddos攻擊:
可以使用gem 'rack-attack'
# In config/application.rb config.middleware.use Rack::Attack
然后新建config/initializers/rack_attack.rb
把這個網址的案例代碼粘體過來https://github.com/kickstarter/rack-attack/wiki/Example-Configuration
還有很多具體設置。如果真的面料大量ddos攻擊,必須購買專業的網絡防火牆。百度安全,雲盾ddos高防IP.
安全分析工具
gem 'brakeman'(4800✨) 一個靜態分享工具。檢查Rails程序的安全弱點。
group :development do
gem 'brakeman'
end
然后在程序根目錄執行brakeman, 或者在非根目錄執行 brakeman /path/to/rails/application
結果是參考,不代表一定是漏洞。需要逐條檢查。
另外gem 也可能有安全漏洞,gem 'bundler-audit'可以檢查(1700✨)
密碼是如何存儲的?