當應用程序首次連接到 Moralis 時,它會使用應用程序 ID 來標識自己。此密鑰作為您的應用程序的一部分提供,任何人都可以從他們的設備反編譯您的應用程序或代理網(wǎng)絡流量以找到它。使用 JavaScript 可以更輕松地利用這一漏洞——只需在瀏覽器中“查看源代碼”并立即找到您的客戶端密鑰。
這就是 Moralis 具有許多其他安全功能來幫助您保護數(shù)據(jù)的原因。
客戶端密鑰已提供給您的用戶,因此任何僅使用客戶端密鑰即可完成的事情對公眾來說是可行的,甚至是惡意黑客。
另一方面,萬能鑰匙絕對是一種安全機制。使用主密鑰可以繞過應用程序的所有安全機制,例如類級別權限和 ACL。擁有主密鑰就像擁有對應用程序服務器的 root 訪問權限,您應該像保護生產機器的 root 密碼一樣熱情地保護您的主密鑰。
總體理念是限制客戶端的權力(使用客戶端密鑰)并執(zhí)行任何需要 Cloud Code 中的主密鑰的敏感操作。您將在標題為“在云代碼中實現(xiàn)業(yè)務邏輯”的部分中學習如何最好地利用這種能力。
最后說明:建議在您的服務器中設置 HTTPS 和 SSL,以避免中間人攻擊,但 Moralis 也適用于非 HTTPS 連接。
第二級安全性是架構和數(shù)據(jù)級別。 在此級別執(zhí)行安全措施將限制客戶端應用程序訪問和創(chuàng)建 Moralis 數(shù)據(jù)的方式和時間。 當您第一次開始開發(fā) Moralis 應用程序時,會設置所有默認值,以便您可以成為更有效率的開發(fā)人員。 例如:
您可以將這些權限中的任何一個配置為適用于所有人、任何人或應用程序中的特定用戶或角色。
角色是包含用戶或其他角色的組,您可以將其分配給對象以限制其使用。 授予角色的任何權限也授予其任何子項,無論他們是用戶還是其他角色,使您能夠為您的應用程序創(chuàng)建訪問層次結構。
一旦你確信你在你的應用程序中擁有正確的類和類之間的關系,你應該開始通過執(zhí)行以下操作來鎖定它:
幾乎您創(chuàng)建的每個類都應該在某種程度上調整這些權限。 對于每個對象都具有相同權限的類,類級別的設置將是最有效的。 例如,一個常見的用例需要擁有一類任何人都可以讀取但沒有人可以寫入的靜態(tài)數(shù)據(jù)。
Moralis 允許您指定每個類允許的操作。 這使您可以限制客戶端訪問或修改您的類的方式。 要更改這些設置,請轉到“數(shù)據(jù)瀏覽器”,選擇一個類,然后單擊“安全”按鈕。
您可以配置客戶端對所選類執(zhí)行以下每個操作的能力:
Get
?:如果用戶知道自己的?objectIds
?,就可以獲取該表中的對象。Find
?:任何擁有 Find 權限的人都可以查詢表中的所有對象,即使他們不知道自己的 ?objectId
?。除非您在每個對象上放置 ACL,否則任何具有公共 Find 權限的表都將完全被公眾讀取。objectId
?。對于上述每個操作,您可以向所有用戶授予權限(這是默認設置),或將權限鎖定到角色和用戶列表。
例如,一個應該對所有用戶都可用的類將通過僅啟用 get 和 find 設置為只讀。 通過只允許創(chuàng)建,可以將日志記錄類設置為只寫。 您可以通過提供對一組特定用戶或角色的更新和刪除訪問權限來啟用用戶生成內容的審核。
鎖定架構和類級別權限后,就該考慮用戶如何訪問數(shù)據(jù)了。 對象級訪問控制使一個用戶的數(shù)據(jù)與另一個用戶的數(shù)據(jù)分開,因為有時一個類中的不同對象需要由不同的人訪問。 例如,用戶的私人個人數(shù)據(jù)應該只有他們才能訪問。
對于那些想要存儲和保護用戶特定數(shù)據(jù)而不需要顯式登錄的應用程序,Moralis 還支持匿名用戶的概念。
當用戶登錄應用程序時,他們會啟動與 Moralis 的會話。 通過此會話,他們可以添加和修改自己的數(shù)據(jù),但無法修改其他用戶的數(shù)據(jù)。
控制誰可以訪問哪些數(shù)據(jù)的最簡單方法是通過訪問控制列表,通常稱為 ACL。 ACL 背后的想法是每個對象都有一個用戶和角色列表以及該用戶或角色擁有的權限。 用戶需要讀取權限(或必須屬于具有讀取權限的角色)才能檢索對象的數(shù)據(jù),并且用戶需要寫入權限(或必須屬于具有寫入權限的角色)才能更新或刪除該對象 目的。
擁有用戶后,您就可以開始使用 ACL。 請記住,可以通過傳統(tǒng)的用戶名/密碼注冊、通過 Facebook 或 Twitter 等第三方登錄系統(tǒng),甚至使用 Moralis 的自動匿名用戶功能來創(chuàng)建用戶。 要將當前用戶數(shù)據(jù)的 ACL 設置為不公開可讀,您所要做的就是:
var user = Moralis.User.current();
user.setACL(new Moralis.ACL(user));
大多數(shù)應用程序都應該這樣做。如果您存儲任何敏感的用戶數(shù)據(jù),例如電子郵件地址或電話號碼,則需要設置這樣的 ACL,以便其他用戶看不到用戶的私人信息。如果一個對象沒有 ACL,那么每個人都可以讀寫。默認情況下,Moralis 在新的用戶對象上設置 ACL,以便只有用戶可以讀取或寫入他們自己的數(shù)據(jù)。 (如果您作為開發(fā)人員需要更新其他 _User 對象,請記住您的主密鑰可以提供執(zhí)行此操作的能力。)
如果您希望用戶擁有一些公開的數(shù)據(jù)和一些私有的數(shù)據(jù),最好有兩個單獨的對象。您可以從公共數(shù)據(jù)中添加指向私有數(shù)據(jù)的指針。
您還可以為類中的不同列設置不同的權限。有關實際演示,請參閱視頻。
當然,您可以對一個對象設置不同的讀寫權限。例如,這是為用戶的公開帖子創(chuàng)建 ACL 的方式,任何人都可以閱讀它:
var acl = new Moralis.ACL();
acl.setPublicReadAccess(true);
acl.setWriteAccess(Moralis.User.current().id, true);
有時在每個用戶的基礎上管理權限是不方便的,并且您希望擁有一組獲得相同待遇的用戶(例如一組具有特殊權力的管理員)。 角色是一種特殊的對象,可讓您創(chuàng)建一組可以全部分配給 ACL 的用戶。 角色的最佳之處在于,您可以在角色中添加和刪除用戶,而無需更新僅限于該角色的每個對象。 要創(chuàng)建只能由管理員寫入的對象:
var acl = new Moralis.ACL();
acl.setPublicReadAccess(true);
acl.setRoleWriteAccess("admins", true);
當然,這個片段假設你已經(jīng)創(chuàng)建了一個名為“admins”的角色。 當您在開發(fā)應用程序時設置了一小組特殊角色時,這通常是合理的。 角色也可以即時創(chuàng)建和更新——例如,在每次連接后將新朋友添加到“friendOf___”角色。
這一切只是一個開始。 應用程序可以通過 ACL 和類級別權限強制執(zhí)行各種復雜的訪問模式。 例如:
這是一個 ACL 的格式,它限制所有者(其 objectId 由“?aSaMpLeUsErId
?”標識)的讀寫權限并允許其他用戶讀取該對象:
{
"*": { "read":true },
"aSaMpLeUsErId": { "read" :true, "write": true }
}
這是使用角色的 ACL 格式的另一個示例:
{
"role:RoleName": { "read": true },
"aSaMpLeUsErId": { "read": true, "write": true }
}
指針權限是一種特殊類型的類級別權限,它根據(jù)存儲在這些對象的指針字段中的用戶,在類中的每個對象上創(chuàng)建一個虛擬 ACL。例如,給定一個具有 owner 字段的類,在 owner 上設置讀取指針權限將使類中的每個對象只能由該對象的 owner 字段中的用戶讀取。對于有發(fā)送者和接收者字段的類,接收者字段的讀指針權限和發(fā)送者字段的讀寫指針權限將使類中的每個對象在發(fā)送者和接收者字段中用戶可讀,可寫僅由用戶在發(fā)件人字段中。
鑒于對象通常已經(jīng)具有指向應該對對象具有權限的用戶的指針,指針權限提供了一種簡單而快速的解決方案,用于使用已經(jīng)存在的數(shù)據(jù)保護您的應用程序,無需編寫任何客戶端代碼或云代碼。
指針權限類似于虛擬 ACL。它們不會出現(xiàn)在 ACL 列中,但如果您熟悉 ACL 的工作原理,則可以將它們視為 ACL。在上面的發(fā)送方和接收方示例中,每個對象的行為就好像它具有以下 ACL:
{
"<SENDER_USER_ID>": {
"read": true,
"write": true
},
"<RECEIVER_USER_ID>": {
"read": true
}
}
請注意,此 ACL 實際上并不是在每個對象上創(chuàng)建的。 當您添加或刪除指針權限時,任何現(xiàn)有的 ACL 都不會被修改,并且任何嘗試與對象交互的用戶只有在指針權限創(chuàng)建的虛擬 ACL 和對象上已經(jīng)存在的真實 ACL 都允許的情況下才能與對象交互 互動。 出于這個原因,將指針權限和 ACL 結合起來有時會讓人感到困惑,因此我們建議對沒有設置很多 ACL 的類使用指針權限。 幸運的是,如果您以后決定使用云代碼或 ACL 來保護您的應用程序,則很容易刪除指針權限。
CLP ?requiresAuthentication
?防止任何未經(jīng)身份驗證的用戶執(zhí)行受 CLP 保護的操作。
例如,如果您想允許經(jīng)過身份驗證的用戶從您的應用程序中查找并獲取公告,并且您的管理員角色擁有所有特權,您可以設置 CLP:
// POST https://my-moralis-dapp.com/schemas/Announcement
// Note: You need to use PUT http method if the class already exists
// Set the X-Parse-Application-Id and X-Parse-Master-Key header
// body:
{
"classLevelPermissions":
{
"find": {
"requiresAuthentication": true,
"role:admin": true
},
"get": {
"requiresAuthentication": true,
"role:admin": true
},
"create": { "role:admin": true },
"update": { "role:admin": true },
"delete": { "role:admin": true }
}
}
影響:
sessionToken
?的用戶)將能夠讀取該類中的所有對象。警告:請注意,這絕不會保護您的內容,如果您允許任何人登錄到您的服務器,每個客戶端仍然可以查詢此對象。
類級別權限 (CLP) 和訪問控制列表 (ACL) 都是保護您的應用程序的強大工具,但它們的交互并不總是與您預期的完全一致。 它們實際上代表了兩個獨立的安全層,每個請求都必須通過這些層才能返回正確的信息或進行預期的更改。 這些層,一個在類級別,一個在對象級別,如下所示。 請求必須通過兩層檢查才能獲得授權。 請注意,盡管行為類似于 ACL,但指針權限是一種類級別權限,因此請求必須通過指針權限檢查才能通過 CLP 檢查。
如您所見,當您同時使用 CLP 和 ACL 時,用戶是否有權發(fā)出請求會變得很復雜。 讓我們看一個示例,以更好地了解 CLP 和 ACL 如何交互。 假設我們有一個 Photo 類,其中包含一個對象 photoObject。 我們的應用中有 2 個用戶,user1 和 user2。 現(xiàn)在假設我們在 Photo 類上設置了 Get CLP,禁用公共 Get,但允許 user1 執(zhí)行 Get。 現(xiàn)在讓我們在 photoObject 上設置一個 ACL 以允許讀取 - 包括 GET - 僅用于 user2。
您可能期望這將允許 user1 和 user2 都獲取 photoObject,但是由于身份驗證的 CLP 層和 ACL 層始終有效,因此實際上它使 user1 和 user2 都無法獲取 photoObject。如果 user1 嘗試獲取 photoObject,它會通過 CLP 層的認證,但會因為沒有通過 ACL 層而被拒絕。同理,如果 user2 試圖獲取 photoObject,也會在 CLP 認證層被拒絕。
現(xiàn)在讓我們看一個使用指針權限的示例。假設我們有一個帶有對象 myPost 的 Post 類。我們的應用中有兩個用戶,poster 和 viewer。假設我們添加了指針權限,允許 Post 類的 Creator 字段中的任何人對該對象進行讀寫訪問,而對于 myPost 對象,poster 是該字段中的用戶。對象上還有一個 ACL,為查看器提供讀取訪問權限。您可能期望這將允許發(fā)布者閱讀和編輯 myPost,并且查看者可以閱讀它,但是查看者將被指針權限拒絕,并且發(fā)布者將被 ACL 拒絕,所以同樣,兩個用戶都無法訪問目的。
由于 CLP、指針權限和 ACL 之間的復雜交互,我們建議在一起使用它們時要小心。僅使用 CLP 來禁用特定請求類型的所有權限,然后將指針權限或 ACL 用于其他請求類型通常很有用。例如,您可能希望為 Photo 類禁用 Delete,但隨后在 Photo 上放置一個指針權限,以便創(chuàng)建它的用戶可以編輯它,而不是刪除它。由于指針權限和 ACL 交互的方式特別復雜,我們通常建議只使用這兩種安全機制中的一種。
Moralis 中有一些特殊的類不遵循與其他所有類相同的所有安全規(guī)則。 并非所有類都完全遵循類級別權限 (CLP) 或訪問控制列表 (ACL) 的定義方式,這里記錄了這些例外情況。
這里,“正常行為”是指 CLP 和 ACL 正常工作,而其他特殊行為在腳注中描述。
?_User ? |
?_Installation ? |
|
Get | normal behavior [1, 2, 3] | ignores CLP, but not ACL |
Find | normal behavior [3] | master key only [6] |
Create | normal behavior [4] | ignores CLP |
Update | normal behavior [5] | ignores CLP, but not ACL [7] |
Delete | normal behavior [5] | master key only [7] |
Add Field | normal behavior | normal behavior |
/server/login
? 不尊重用戶類上的 Get CLP。登錄僅基于用戶名和密碼,不能使用 CLP 禁用。
/server/users/me
?,不尊重用戶類上的 Get CLP。
installationId
?作為約束,否則不允許查找沒有主密鑰的請求。對于大多數(shù)應用程序,您只需要關心密鑰、類級權限和對象級 ACL 即可確保您的應用程序和用戶數(shù)據(jù)的安全。但是,有時,您會遇到它們還不夠的邊緣情況。對于其他一切,有 Cloud Code。
Cloud Code 允許您將 JavaScript 上傳到 Moralis 的服務器,我們將為您運行它。與在用戶設備上運行的可能已被篡改的客戶端代碼不同,Cloud Code 保證是您編寫的代碼,因此可以承擔更多責任。
Cloud Code 的一個特別常見的用例是防止存儲無效數(shù)據(jù)。對于這種情況,惡意客戶端不能繞過驗證邏輯尤為重要。
要創(chuàng)建驗證函數(shù),Cloud Code 允許您為您的類實現(xiàn) beforeSave 觸發(fā)器。每當保存對象時都會運行這些觸發(fā)器,并允許您修改對象或完全拒絕保存。例如,這是您創(chuàng)建 Cloud Code beforeSave 觸發(fā)器以確保每個用戶都設置了電子郵件地址的方式:
Moralis.Cloud.beforeSave('_User', request => {
const user = request.object;
if (!user.get("email")) {
throw "Every user must have an email address.";
}
});
驗證可以鎖定您的應用程序,以便只接受某些值。 您還可以使用 afterSave 驗證來規(guī)范化您的數(shù)據(jù)(例如,以相同的方式格式化所有電話號碼或貨幣)。 您可以保留直接從客戶端應用程序訪問 Moralis 數(shù)據(jù)的大部分生產力優(yōu)勢,但您也可以動態(tài)為您的數(shù)據(jù)強制執(zhí)行某些不變量。
需要驗證的常見場景包括:
雖然驗證在 Cloud Code 中通常很有意義,但某些操作可能特別敏感,應盡可能小心謹慎。在這些情況下,您可以完全刪除客戶端的權限或邏輯,而是將所有此類操作集中到 Cloud Code 函數(shù)中。
當調用云代碼函數(shù)時,它可以使用可選的 {?useMasterKey:true
?} 參數(shù)來獲得修改用戶數(shù)據(jù)的能力。使用主密鑰,您的 Cloud Code 函數(shù)可以覆蓋任何 ACL 并寫入數(shù)據(jù)。這意味著它將繞過您在前面部分中設置的所有安全機制。
假設您希望允許用戶“喜歡”一個 Post 對象,而不給予他們對該對象的完全寫入權限。您可以通過讓客戶端調用 Cloud Code 函數(shù)而不是修改 Post 本身來做到這一點:
應謹慎使用萬能鑰匙。僅在需要安全覆蓋的單個 API 函數(shù)調用中將 ?useMasterKey
?設置為 ?true
?:
Moralis.Cloud.define("like", async request => {
var post = new Moralis.Object("Post");
post.id = request.params.postId;
post.increment("likes");
await post.save(null, { useMasterKey: true })
});
Cloud Code 的一個非常常見的用例是向特定用戶發(fā)送推送通知。 一般來說,不能信任客戶端直接發(fā)送推送通知,因為他們可以修改警報文本,或推送給他們不應該發(fā)送的人。 您的應用程序設置將允許您設置是否啟用“客戶端推送”; 我們建議您確保它已被禁用。 相反,您應該編寫 Cloud Code 函數(shù),在發(fā)送推送之前驗證要推送和發(fā)送的數(shù)據(jù)。
默認情況下,Moralis 允許任何 SDK 用戶通過創(chuàng)建新類和更改現(xiàn)有類的結構來修改數(shù)據(jù)庫。
這在開發(fā)階段非常有用,但在您投入生產時應該關閉,以保護您的數(shù)據(jù)庫免受垃圾郵件的影響(以防有人使用 SDK 用新的類填充您的數(shù)據(jù)庫或向現(xiàn)有列添加大量列)。
這可以在服務器設置中完成。
Moralis 為您提供了多種方法來保護應用程序中的數(shù)據(jù)。在構建應用程序并評估要存儲的數(shù)據(jù)類型時,您可以決定選擇哪種實現(xiàn)方式。
您應用程序中的大多數(shù)類都屬于幾個易于保護的類別之一。對于完全公開的數(shù)據(jù),您可以使用類級別的權限來鎖定表,使其不受任何人的公開可讀和可寫。對于完全私有的數(shù)據(jù),您可以使用 ACL 來確保只有擁有數(shù)據(jù)的用戶才能讀取它。但有時,您會遇到不想要完全公開或完全私有的數(shù)據(jù)的情況。例如,您可能有一個社交應用程序,其中您有一個用戶的數(shù)據(jù),這些數(shù)據(jù)應該僅供他們認可的朋友閱讀。為此,您需要結合本指南中討論的技術來準確啟用您想要的共享規(guī)則。
我們希望您能使用這些工具盡一切可能保護您的應用數(shù)據(jù)和用戶數(shù)據(jù)的安全。一起,我們可以讓網(wǎng)絡成為一個更安全的地方。
更多建議: