Zabezpieczanie Breeze na serwerze, aby zapobiec złośliwym aktualizacjom kluczy obcych
Próbuję tylko ustalić, ile z własnego bezpieczeństwa muszę zaimplementować po stronie serwera podczas zapisywania zmian w Breeze. W szczególności myślę o tym, jak złośliwy użytkownik może ręcznie włamać się do żądania SaveChanges lub włamać javascript do klienta, aby ominąć moje normalne reguły biznesowe - na przykład, aby złośliwie zmienić identyfikatory kluczy obcych w moich jednostkach.
Chcę dokładnie zrozumieć, gdzie muszę skoncentrować swoje wysiłki bezpieczeństwa; Nie chcę tracić czasu na wdrażanie warstw zabezpieczeń, które nie są wymagane.
Używam Breeze z .net i Entity Framework po stronie serwera.
PrzykładOto trywialny przykład.ObjectA
ma odniesienie doObjectB
, iObjectA
jest własnością konkretnegoUser
. Moja baza danych wygląda tak:
ObjectA:
Id ObjectB_Id SomeField User_Id
1 1 Alice's ObjectA 1
2 2 Bob's ObjectA 2
ObjectB:
Id SomeOtherField
1 Foo
2 Bar
User:
Id Name
1 Alice
2 Bob
Z tego modelu mam problemy związane z bezpieczeństwem:
Nie chcę, aby nieuwierzytelnieni użytkownicy zmienili jakiekolwiek daneNie chcę, żeby Bob mógł dokonywać jakichkolwiek zmian w AlicjiObjectA
Nie chcę, żeby Alice próbowała ją wskazaćObjectA
u BobaObjectB
.Nie chcę, żeby Bob próbował zmienićUser_Id
na jegoObjectA
być Alice.Rozwiązanie dla (1) jest banalne; Zapewnię, że moja metoda SaveChanges ma[Authorize]
atrybut.
Mogę łatwo użyć Fiddlera do zbudowania żądania SaveChanges w celu odtworzenia problemów od 2 do 4 - na przykład mogę zbudować żądanie, które się zmieniaAlice
jest ObjectA wskazujący na BobaObjectB
. Oto jak może wyglądać treść wiadomości:
"entities":
[
{
"Id":1,
"ObjectB_Id":2,
"SomeField":"Alice's ObjectA",
"User_Id":1,
"entityAspect":
{
"entityTypeName":"ObjectA:#MyNamespace",
"defaultResourceName":"ObjectAs",
"entityState":"Modified",
"originalValuesMap":
{
"ObjectB_Id":"1"
},
"autoGeneratedKey":
{
"propertyName":"Id",
"autoGeneratedKeyType":"Identity"
}
}
}
],
Tak jak się spodziewałem, gdy żadne zabezpieczenia nie są implementowane po stronie serwera, utrzymuje się zaktualizowana wartość dlaObjectB_Id
do bazy danych.
Jednak potwierdziłem to również, jeśli nie ma wpisuObjectB_Id
woriginalValuesMap
, a nawet jeśli zmienię wartość dlaObjectB_Id
w głównej części wiadomości NIE jest aktualizowany w bazie danych.
Myślę, że oznacza to, że ogólne zasady bezpieczeństwa, których muszę przestrzegać na serwerze, to:
[Edytowane 4 lipca 2013 r. - przepisane dla większej przejrzystości]
Ogólnie:
Nic w wiadomości nie może być zaufane: ani wartości w originalValuesMap, ani rzekomo „niezmienione” wartościJedynym wyjątkiem jest tożsamość podmiotu, którą możemy założyć, że jest poprawna.Podobno „niezmienione” właściwości mogły zostać naruszone, nawet jeśli nie znajdują się w originalValuesMapDla właściwości „niezmienionych” (właściwości, które nie znajdują się również w originalValuesMap):
Kiedy „używamy” dowolnej „niezmienionej” właściwości, NIE wolno nam używać wartości z komunikatu; musimy pobrać obiekt z bazy danych i użyć wartości z tego.na przykład podczas sprawdzania własności obiektu w celu upewnienia się, że użytkownik może go zmienić, nie możemy ufać identyfikatorowi użytkownika w wiadomości; musimy pobrać obiekt z bazy danych i użyć wartości UserId z tegoDla każdej innej „niezmienionej” właściwości, której nie używamy w żaden sposób, nie musimy się martwić, jeśli została naruszona, ponieważ nawet jeśli tak, zmieniona wartość nie zostanie utrwalona w bazie danychDla zmienionych właściwości (właściwości, które znajdują się również w originalValuesMap):
Reguły biznesowe mogą uniemożliwiać zmianę określonych właściwości. Jeśli tak jest, powinniśmy wdrożyć kontrolę dla każdej takiej reguły.
Jeśli dozwolona jest zmiana wartości i jest to klucz obcy, prawdopodobnie powinniśmy przeprowadzić kontrolę bezpieczeństwa, aby upewnić się, że nowa wartość może być używana przez tożsamość sesji
Nie możemy używać żadnych oryginalnych wartości w originalValuesMap, ponieważ mogły one zostać naruszone
[Koniec edycji]
Wdrażanie zasadZakładając, że te zasady są poprawne, myślę, że istnieje kilka opcji implementacji zabezpieczeń wokół zmienionych kluczy obcych:
Jeśli reguły biznesowe nie zezwalają na zmiany w określonym polu, odrzucę żądanie SaveChangesJeśli reguły biznesowe zezwalają na zmiany w określonym polu, sprawdzę, czy nowa wartość jest dozwolona. Robiąc to, NIE MOŻNA użyćoriginalValuesMap
; Muszę przejść do bazy danych (lub innego zaufanego źródła, np. Sesji Cookie)Zastosowanie tych zasad do obaw dotyczących bezpieczeństwa, które podałem powyżej,
problem bezpieczeństwa (2). Będę musiał sprawdzić tożsamość użytkownika w sesji przeciwkoUser_ID
naObjectA
który jest obecnie w bazie danych. Dzieje się tak, ponieważ nie mogę ufać ID_użytkownika na żądanie, nawet jeśli nie ma go woriginalValuesMap
.
problem bezpieczeństwa (3). Jeśli reguły biznesowe pozwalają na zmianęObjectB
, Muszę sprawdzić, kto jest właścicielem nowej wartościObjectB_Id
; Zrobię to, pobierając określony obiekt B z bazy danych. Jeśli toObjectB
nie jest własnościąObjectA
właściciela, prawdopodobnie chcę odrzucić zmiany.
problem bezpieczeństwa (4). Jeśli reguły biznesowe pozwalają na zmianęUser
, jest to już objęte (2).
Tak więc, naprawdę szukam potwierdzenia, że myślę zgodnie z właściwą linią.
Czy moje ogólne zasady są prawidłowe?Czy moje wdrożenie zasad brzmi rozsądnie?Czy coś mi brakuje?Czyżbym komplikował rzeczy?