Hashing SQL Serverrel

Véletlen belefutottam egy T-SQL függvénybe, amit úgy hívnak, hogy HashBytes. Ez képes MD2, MD4, MD5, SHA és SHA1 hasht gyártani varchar, nvarchar és varbinary értékekből vagy változókból.

DECLARE @str varchar(10) = 'mintaminta'
SELECT HASHBYTES('MD5', @str)

Ez azt mondja, hogy 0x94B15DFD3AA83BBBB3B79DED6D57259F. Ráadásul a hashing algoritmus is paraméterezhető, azaz a rendszer megeszi ezt is:

DECLARE @str varchar(10) = 'mintaminta', @alg varchar(4) = 'SHA1'
SELECT HASHBYTES(@alg, @str)

De mire jó a hash? Ez egy egyirányú transzformációja értékeknek (pontosabban a transzformációnak, azaz hashelésnek az eredménye), ahol az eredménynek ránézésre semmi köze nincs a bemenethez. Két nagy halmazra lehet bontani a hash algoritmusokat: olyanokra, ahol nagy valószínűséggel vannak egyforma értékek különböző bemeneteknél, és olyanokra, ahol nagy valószínűséggel nincsenek. Előbbieket csoportok képzésére szokták használni, például keresést elősegítendő: az elemeket hasheljük, és a hashnek megfelelő dobozba tesszük. Ha valaki keres egy elemet, akkor csinál egy hasht, és megnézi az adott hash-sel rendelkező dobozban, hogy van-e olyan elem. Ez DBA-knak hatékonytalannak tűnhet, de nem lehet mindenkinek egy SQL Server a zsebében.

A második csoport egyik esete a “titkosítás”. Azért teszem idézőjelbe, mert a régi hashekre általában létezik “workaround”, azaz ki lehet trükközni őket. Itt az a lényeg, hogy két különböző bemenetnek tök különböző kimenete van, a legkisebb változtatás a bemeneten teljesen megváltoztatja a kimenetet, előre megjósolhatatlan módon. Például jelszavak helyett szokás a jelszavak hashét tárolni. Azonosításnál a szerver megint hashel, és ha stimmel a hash, akkor az azonosítást sikeresnek veszi. Ez jó, mert azok, akik hozzáférnek az adatbázishoz sem tudnak visszaélni a jelszóval. Baj akkor van, ha valaki képes egy hash alapján bemenetet gyártani, azaz a definíció szerint egyirányú függvényt kétirányúsítja. Ekkor ugyanis az egész módszer varázsát (és hasznát) veszíti. Ez a hash collision, azaz összekavarás ütközés magyarul.

Amúgy ezt nem a summiton tanultam, csak most van időm olvasni – azért jólesik rájönni, hogy mégiscsak töltök időt a családommal :)

UPDATE:
Ha valakinek a “klasszikus”, azaz nem bináris, hanem string hash kell, azt a következő módon tudja kicsiholni:

DECLARE @str varchar(10) = 'mintaminta', @alg varchar(4) = 'SHA1'
SELECT HASHBYTES(@alg, @str)
SELECT SUBSTRING(master.sys.fn_sqlvarbasetostr(HASHBYTES(@alg, @str)),3,128)

Tessék észrevenni, hogy a kettő ugyanaz szemmel olvasásra (leszámítva a hexa előtagot a binárisban, amit a substringgel vágtunk le).

Error 18456, Level 14, state – SQL Server login errors

(Magyarul itt)
Occasionally it happens that someone is unable to log in to SQL Server because they mistyped the password, have no permission, etc. This is not a problem – as long as we know what is the blocking issue. But how about someone being cocksure they’re trying the correct user, password ,server, etc and still failing? The most straightforward solution is my favorite, reading the SQL errorlog, once again. If the server is set to audit failed logins (and this is the default), you can find the error in the errorlog as well, not on the client side only:

Msg 18456, Level 14, State 1, Server DEMOSQL1, Line 1
Login failed for user ‘tygger’

Actually, something better gets in to the log, but first, let’s analyze the first line, that is ,the first three numbers of the error. the first one is the error number, the identifier of the error; the second is the severity, that is, how bad it is. The bigger the number the worse it is. If you see something above 19, you might be in real trouble. The third number is the state, which is an interesting species. This can be used to provide diagnostic information, like throwing an error with state 1 from an SP and with state 2 from parameterized query. It can make DBAs (and developers) life easier. Now back to that errorlog!
Continue reading ‘Error 18456, Level 14, state – SQL Server login errors’ »

Hogyan rejtsük el az adatbázisokat

Pár hete megkeresett egy szak- és sorstársunk, az aktív-aktív clusterről zengett ódáim kapcsán, és megkérezte, hogy hogyan tudná smucig ügyfelét boldoggá tenni. A felállás a következő: van egy cluster, és nem aktív-aktív clustert szeretnének, hanem több SQL instance-t az adott resource groupba, hogy spóroljanak. A cél az, hogy különböző felhasználóknak az az élményük legyen, hogy senki más nem használja az adott SQL szervert. Az alábbiakban leírom, hogy miért NEM lehet ezt szépen megcsinálni.

Mi is az SQL cluster alapgondolata? Van egy resource group, benne pár diszk, egy IP cím meg egy hálózati név, és az egészre ráteszek egy SQL szervert. Mi lenne, ha hasonlóan a standalone szervereken használt named instance-hoz, még egy SQL szervert telepítenénk? A gondolat jó, de sajnos ez nem működik by design. A BOL ezt írja róla konkrétan: ” Each resource group can contain at most one instance of SQL Server.” Mi ennek az oka? Hát, nekem az jutott eszembe, hogy ha clustert építek, akkor nagy rendelkezésreállást akarok. Ha két instance-t telepítek ugyanabba a resource groupba, akkor azok együtt kell, h billenjenek, tehát ha A instance megdöglik, és elbillen a cluster, akkor viszi B instance-t is, kis szünetet okozva. Ha valamelyik diszk hal meg, az meg pláne kinyír mindent. Szóval így erős függés alakulhat ki a két instance között, és pont ezt akarja elkerülni a technológia.

Tehát zsákutca. Akkor nézzünk más megoldást. Közismert, hogy az SQL 2005-ben a security alrendszert fantasztikusan kibővítették, hihetetlen dolgokat lehet megtenni benne. Úgyhogy nézzünk is gyorsan körül, és találjuk meg a következő jogot: VIEW ANY DATABASE. Ha ezt revoke-oljuk, akkor mi történik? Hősünk csak az általa használható adatbázisokat látja a sys.databases táblában, ezzel együtt a Management Studio adatbázis-választó dropdown listája is beszűkül a megfelelő adatbázisokra. Ez nagyon jól hangzik, de a szigorítás sajnos túl jól sikerül. Az Object Explorerben baloldalt ugyanis eltűnik az összes adatbázis, csak a master és a tempdb látszik. Így emberünknek nincs meg az az illúziója, hogy ő egy dedikált szerveren dolgozik, az viszont megvan, hogy széjjelpolicyzta valaki. Ez a kis tüske benne van 2005-ben és 2008-ban is (R2-ben is), a Microsoft azt mondja, hogy majd egy következő major release-ben foglalkoznak vele (2011 vagy 2014 vagy efféle). Tökéletesen működő megoldás tehát nincs, ám teljesen meglepő módon a legjobb eredményt SQL 2000 Query Analyzerrel lehet elérni. Annak az Object Explorere megmutatja az adatbázisokat is megfelelően, rejtély, hogy hova tűnt ez 2005 táján. Az alábbi képen jól látható, hogy a foo userrel belépve a dropdown list jó, az Object Explorerben viszont nem látszik a foo adatbázis.

Hab a tortán: nem bírtam magammal, és elindítottam egy Profilert, hogy megnézzem, mit kérdez a kliens, amitől eltűnnek az adatbázisok az OE-ből. Semmit. Az Object Explorer refreshkor futó T-SQL lekérdezésben ott van benne rendesen a kis privát adatbázisom, de valamiért a gonosz kliens szoftver ezt megeszi. A Microsoft Connecten van már egy item arról, hogyan kéne működnie. Én részemről inkább bugnak tekintem, mint feature requestnek, de ez az én konzervativizmusom. Mindenkinek, aki szeretne ezzel játszani, egy kiváló minta script, Aaron Bertrandtól, aki szintén morcos volt egy kicsit.

USE [master];
GO
CREATE DATABASE foo;
GO
CREATE DATABASE bar;
GO
CREATE LOGIN [foo] WITH
    PASSWORD = N'foo',
    DEFAULT_DATABASE = [foo],
    CHECK_EXPIRATION = OFF,
    CHECK_POLICY = OFF;
GO
CREATE LOGIN [bar] WITH
    PASSWORD = N'bar',
    DEFAULT_DATABASE = [bar],
    CHECK_EXPIRATION = OFF,
    CHECK_POLICY = OFF;
GO
USE [foo];
GO
CREATE USER [foo]
    FOR LOGIN [foo]
    WITH DEFAULT_SCHEMA = [dbo];
GO
USE [bar];
GO
CREATE USER [bar]
    FOR LOGIN [bar]
    WITH DEFAULT_SCHEMA = [dbo];
GO
USE [master];
GO
DENY VIEW ANY DATABASE TO [foo];
DENY VIEW ANY DATABASE TO [bar];
GO

Ha már más tollával ékeskedem, meg kell jegyeznem, hogy ha a fent említett foo vagy bar usereket dbo-vá (nem db_ownerré) tesszük, akkor elvárás szerint működik a dolog:

USE foo;
GO
DROP USER foo;
GO
USE bar;
GO
DROP USER bar;
GO
USE [master];
GO
ALTER AUTHORIZATION ON DATABASE::foo TO [foo];
ALTER AUTHORIZATION ON DATABASE::bar TO [bar];
GO

Apró probléma: egy adatbázisnak csak egy dbo-ja lehet. De legalább kicsit workaroundoltuk.

CIS SQL Server 2005 Security Benchmark – ne feleselj!

A múltkoriban volt szerencsém a Center of Internet Security nevű szervezet egy iparban több helyen használatos SQL security ajánlását kielemeznem megvalósíthatóság szempontjából. Az eredmény igen érdekes, ámde nem meglepő lett: bizonyos helyeken a “kössük meg a rendszergazda kezét is, tegyünk rá bilincset is, majd vágjuk le” szemlélet ütött ki, míg máshol már-már alapvető dolgokról feledkeztek el (mint országos cimborám, az SQL Browser teljes megsemmisítése). A DAC és a linked server letiltása mondjuk két olyan dolog, hogy engem megleptek vele, bár biztos van olyan trace flag, ami letiltja a DAC-ot.

A jóleső sznob fikázáson túl viszont el kell ismernem, egész jó a doksi, persze le kell szögeznem, a security szó kétszer akkora betűvel látszik, mint az SQL, és ha valakinek volt kételye, hogy a biztonságnak ára van, akkor az itt most el kell, hogy oszoljon, amikor több tonna auditlogot fog gyártani a szervere, majd leáll, amikor betelt a diszk :) Viszont mivel pozitív srác vagyok, egyrészt leírtam magunknak, hogy mit hogy kell/lehet implementálni a benchmarkból, plusz amivel nem értettem egyet, azt megírtam a CI Security-nak, néhány egyéb javaslat mellett. Gondoltam, hogy ha csak meggondolják, már megérte, én meg megnyugszom tőle, mert onnantól kezdve rajtam nem múlhat, hogy jó legyen a benchmark. Na, erre visszanyalt a fagyi. Gyakorlatilag azt mondta az ottani ember, hogy ha olyan okos vagyok, akkor üljek be az ajánlásgyártó csoportba. Ez egyrészt nagyon hízelgő, májam ki is ütötte az oldalamat, másrészt viszont valamikor élnem is kéne, úgyhogy most gondolkozom, hogy mit is mondjak erre az ajánlatra…

SQL Server and forgotten sysadmin passwords

Up to SQL 2005, the sysadmin role contains the local Adminstrators group by default (and by design), under the name BUILTIN\Administrators. This bothered some folks as it wasn’t secure enough for them, so the SQL 2008 asks you during the install who should be the member of the sysadmin role, no automatic membership granted to local admins. This is a pretty well-known feature.

However, it it lesser known that if you start the SQL Server in a single user, minimal mode (sqlservr -m -c started from the directory of the program directory, you can see it at the installed service), the local admins become sysadmins, independently of their normal privileges. This can be a failsafe solution, for example in an over-hardened environment where someone accidentally lost the password of the renamed and disabled sa account, which was the only sysadmin. You can reset passwords, add new sysadmins or whatever you want.