Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Şunlar için geçerlidir:SQL Server
Azure SQL Veritabanı
Azure SQL Yönetilen Örneği
Azure Synapse Analytics
Analytics Platform Sistemi (PDW)
Microsoft Fabric SQL veritabanı
SQL enjeksiyonu, daha sonra ayrıştırılmak ve yürütülmek üzere SQL Server Veritabanı Motoru örneğine geçirilen dizelere kötü amaçlı kodun eklenmesiyle gerçekleştirilen bir saldırıdır. SQL deyimlerini oluşturan tüm yordamlar, SQL enjeksiyon güvenlik açıkları açısından gözden geçirilmelidir; çünkü Veritabanı Motoru, geçerli söz dizime sahip tüm sorguları yürütür. Parametreli veriler bile becerikli ve kararlı bir saldırgan tarafından değiştirilebilir.
SQL ekleme nasıl çalışır?
SQL eklemenin birincil biçimi, SQL komutları ile birleştirilmiş ve yürütülen kullanıcı girişi değişkenlerine doğrudan kod eklenmesinden oluşur. Daha az doğrudan saldırı, bir tabloda veya meta veri olarak depolamayı hedefleyen dizelere kötü amaçlı kod ekler. Depolanan dizeler daha sonra dinamik bir SQL komutuyla birleştirildiğinde, kötü amaçlı kod yürütülür.
Ekleme işlemi, bir metin dizesini erken sonlandırarak ve yeni bir komut ekleyerek çalışır. Eklenen komut yürütülmeden önce ona ek dizeler eklenebilir, bu yüzden kötü amaçlı kişi eklenen dizeyi bir açıklama işaretiyle --sonlandırır. Yürütme sırasında sonraki metin yoksayılır.
Aşağıdaki betikte basit bir SQL enjeksiyonu gösterilmektedir. Betik, sabit kodlanmış dizeleri kullanıcı tarafından girilen bir dizeyle birleştirerek bir SQL sorgusu oluşturur:
var ShipCity;
ShipCity = Request.form ("ShipCity");
var sql = "select * from OrdersTable where ShipCity = '" + ShipCity + "'";
Kullanıcıdan bir şehrin adını girmesi istenir. Eğer Redmond girerlerse, betik tarafından oluşturulan sorgu aşağıdaki örneğe benzer:
SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond';
Ancak, kullanıcının aşağıdaki metni girdiğinizi varsayalım:
Redmond';drop table OrdersTable--
Bu durumda, betik aşağıdaki sorguyu oluşturur:
SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond';drop table OrdersTable--'
Noktalı virgül (;), bir sorgunun sonunu ve başka bir sorgunun başlangıcını belirtir. Çift çizgi (--), mevcut satırın geri kalanının yorum olarak değerlendirildiğini ve görmezden gelinmesi gerektiğini gösterir. Değiştirilen kodun söz dizimi doğruysa, sunucu tarafından yürütülür. Veritabanı Altyapısı bu ifadeyi işlerken, önce OrdersTable'ın ShipCity olduğu Redmond içindeki tüm kayıtları seçer. Ardından, Veritabanı Motoru OrdersTable'yi kaldırır.
Eklenen SQL kodu sözdizimi açısından doğru olduğu sürece, kurcalama programatik olarak algılanamaz. Bu nedenle, tüm kullanıcı girişlerini doğrulamanız ve kullandığınız sunucuda yerleşik SQL komutlarını yürüten kodu dikkatle gözden geçirmeniz gerekir. Kodlama en iyi yöntemleri bu makaledeki aşağıdaki bölümlerde açıklanmıştır.
Tüm girişleri doğrulama
Tür, uzunluk, biçim ve aralığı test ederek her zaman kullanıcı girişini doğrulayın. Kötü amaçlı girişlere karşı önlemler uyguladığınızda uygulamanızın mimari ve dağıtım senaryolarını göz önünde bulundurun. Güvenli bir ortamda çalışacak şekilde tasarlanmış programların güvenli olmayan bir ortama kopyalanabileceğini unutmayın. Aşağıdaki öneriler en iyi yöntemler olarak değerlendirilmelidir:
Uygulamanız tarafından alınan verilerin boyutu, türü veya içeriği hakkında hiçbir varsayımda bulunun. Örneğin, aşağıdaki değerlendirmeyi yapmalısınız:
Hatalı veya kötü amaçlı bir kullanıcı, uygulamanızın posta kodu beklediği 2 GB'lık bir video dosyasına girerse uygulamanız nasıl davranır?
Bir
DROP TABLEdeyim bir metin alanına eklenmişse uygulamanız nasıl davranır?
Girişin boyutunu ve veri türünü test edin ve uygun sınırları uygulayın. Kasıtlı arabellek taşmalarını önlemeye bu yardımcı olabilir.
Dize değişkenlerinin içeriğini test edin ve yalnızca beklenen değerleri kabul edin. İkili veriler, kaçış dizileri ve açıklama karakterleri içeren girişleri reddedin. Bu, betik eklemeyi önlemeye ve bazı arabellek taşması açıklarına karşı koruma sağlamaya yardımcı olabilir.
XML belgeleriyle çalışırken, girilen tüm verileri şemasına göre doğrulayın.
Transact-SQL deyimlerini hiçbir zaman doğrudan kullanıcı girişinden derlemeyin.
Kullanıcı girişini doğrulamak için saklı yordamları kullanın.
Çok katmanlı ortamlarda, güvenilen bölgeye giriş öncesinde tüm verilerin doğrulanması gerekir. Doğrulama işlemini geçmeyen veriler reddedilmeli ve önceki katmana bir hata döndürülmelidir.
Birden çok doğrulama katmanı uygulayın. Rastgele kötü amaçlı kullanıcılara karşı alacağınız önlemler, belirlenen saldırganlara karşı etkisiz olabilir. Daha iyi bir uygulama, kullanıcı arabiriminde ve bir güven sınırını aştığı sonraki tüm noktalarda girişi doğrulamaktır.
Örneğin, istemci tarafı uygulamasında veri doğrulaması basit betik eklemeyi engelleyebilir. Ancak, bir sonraki katman girdisinin zaten doğrulandığını varsayarsa, istemciyi atlayan tüm kötü amaçlı kullanıcılar sisteme sınırsız erişime sahip olabilir.
Doğrulanmamış kullanıcı girişini hiçbir zaman birleştirmeyin. Dize birleştirme, betik ekleme için birincil giriş noktasıdır.
Dosya adlarının oluşturulabileceği alanlarda aşağıdaki dizeleri kabul etmeyin:
AUX,CLOCK$,COM1aracılığıylaCOM8,CON, ,CONFIG$,LPT1aracılığıylaLPT8,NULvePRN.
Mümkünse, aşağıdaki karakterleri içeren girişi reddedin.
| Giriş karakteri | Transact-SQL'nin Anlamı |
|---|---|
; |
Sorgu sınırlayıcısı. |
' |
Karakter veri dizesi sınırlayıcısı. |
-- |
Tek satırlı açıklama sınırlayıcısı. Bu satırın sonuna kadar izleyen -- metin sunucu tarafından değerlendirilmez. |
/*** ... ***/ |
Yorum sınırlayıcıları. ile /* arasındaki */ metin sunucu tarafından değerlendirilmez. |
xp_ |
Katalog genişletilmiş saklı yordamlarının adının başında xp_cmdshell kullanılır. |
Tür açısından güvenli SQL parametrelerini kullanma
Parameters Veritabanı Altyapısı'ndaki koleksiyon, tür denetimi ve uzunluk doğrulaması sağlar. Koleksiyonu kullanırsanız Parameters , giriş yürütülebilir kod yerine değişmez değer olarak değerlendirilir. Koleksiyonu kullanmanın Parameters bir diğer avantajı da tür ve uzunluk denetimlerini zorunlu kılmanızdır. Aralığın dışındaki değerler bir özel durum tetikler. Aşağıdaki kod parçası koleksiyonun Parameters kullanılmasını gösterir:
SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", conn);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id",
SqlDbType.VarChar, 11);
parm.Value = Login.Text;
Bu örnekte, @au_id parametresi yürütülebilir kod yerine değişmez bir değer olarak değerlendirilir. Bu değer, tür ve uzunluk açısından denetlendi. değeri @au_id belirtilen tür ve uzunluk kısıtlamalarıyla uyumlu değilse, bir özel durum oluşturulur.
Saklı yordamlarla parametreli giriş kullanma
Saklı yordamlar, filtrelenmemiş giriş kullanıyorsa SQL enjeksiyonlarına karşı savunmasız olabilir. Örneğin, aşağıdaki kod savunmasızdır:
SqlDataAdapter myCommand =
new SqlDataAdapter("LoginStoredProcedure '" + Login.Text + "'", conn);
Saklı yordamlar kullanıyorsanız, giriş olarak parametreleri kullanmanız gerekir.
Parameters koleksiyonunu dinamik SQL ile kullanma
Saklı yordamları kullanamıyorsanız, aşağıdaki kod örneğinde gösterildiği gibi parametreleri kullanmaya devam edebilirsiniz.
SqlDataAdapter myCommand = new SqlDataAdapter(
"SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", conn);
SqlParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id",
SqlDbType.VarChar, 11);
parm.Value = Login.Text;
Filtre girişi
Girişi filtrelemek, kaçış karakterlerini kaldırarak SQL eklemeye karşı koruma sağlamada da yararlı olabilir. Ancak, sorun oluşturabilecek çok sayıda karakter nedeniyle filtreleme güvenilir bir savunma değildir. Aşağıdaki örnek karakter dizesi sınırlayıcısını arar.
private string SafeSqlLiteral(string inputSQL)
{
return inputSQL.Replace("'", "''");
}
LIKE yan tümceleri
LIKE tümcesi kullanıyorsanız, joker karakterlerden yine de kaçış yapılması gerekir.
s = s.Replace("[", "[[]");
s = s.Replace("%", "[%]");
s = s.Replace("_", "[_]");
SQL enjeksiyonu kodunu gözden geçirme
EXECUTE, EXEC veya sp_executesql çağıran tüm kodları gözden geçirmelisiniz. Bu deyimleri içeren yordamları belirlemenize yardımcı olması için aşağıdakine benzer sorgular kullanabilirsiniz. Bu sorgu, EXECUTE veya EXEC sözcüklerinden sonra 1, 2, 3 veya 4 boşluk olup olmadığını denetler.
SELECT object_Name(id)
FROM syscomments
WHERE UPPER(TEXT) LIKE '%EXECUTE (%'
OR UPPER(TEXT) LIKE '%EXECUTE (%'
OR UPPER(TEXT) LIKE '%EXECUTE (%'
OR UPPER(TEXT) LIKE '%EXECUTE (%'
OR UPPER(TEXT) LIKE '%EXEC (%'
OR UPPER(TEXT) LIKE '%EXEC (%'
OR UPPER(TEXT) LIKE '%EXEC (%'
OR UPPER(TEXT) LIKE '%EXEC (%'
OR UPPER(TEXT) LIKE '%SP_EXECUTESQL%';
QUOTENAME() ve REPLACE() ile parametreleri sarmalama
Seçilen her saklı yordamda, dinamik Transact-SQL içinde kullanılan tüm değişkenlerin doğru işlendiğini doğrulayın. Saklı yordamın giriş parametrelerinden gelen veya bir tablodan okunan veriler, QUOTENAME() veya REPLACE() içinde sarmalanmalıdır. Unutmayın ki içine geçirilen QUOTENAME() değerinin, sysname olduğunu ve maksimum 128 karakter uzunluğunda olduğunu.
| @variable | Önerilen sarıcı |
|---|---|
| Güvenliği sağlanabilir bir ad | QUOTENAME(@variable) |
| = 128 karakterlik <dize | QUOTENAME(@variable, '''') |
| 128 karakterlik > dize | REPLACE(@variable,'''', '''''') |
Bu tekniği kullandığınızda, bir SET deyim aşağıdaki gibi düzeltilebilir:
-- Before:
SET @temp = N'SELECT * FROM authors WHERE au_lname ='''
+ @au_lname + N'''';
-- After:
SET @temp = N'SELECT * FROM authors WHERE au_lname = '''
+ REPLACE(@au_lname, '''', '''''') + N'''';
Veri kesilmesi yoluyla etkinleştirilen enjeksiyon
Bir değişkene atanan herhangi bir dinamik Transact-SQL, bu değişken için ayrılan arabellekten daha büyükse kesintiye uğrar. Bir saklı yordama beklenmedik şekilde uzun dizeler geçirerek ifade kısaltmayı zorlayabilen bir saldırgan sonucu manipüle edebilir. Örneğin, aşağıdaki örnek saklı yordam, kısaltma nedeniyle etkinleştirilen enjeksiyona karşı savunmasızdır.
Bu örnekte en fazla 200 karakter uzunluğunda bir @command arabelleğe sahibiz. Parola için toplam 154 karaktere ihtiyacımız vardır: 'sa' deyimi için 26, UPDATE yan tümcesi için 16, WHERE için 4 ve 'sa' tırnak işaretleri için 2: 200 - 26 - 16 - 4 - 2 = 154. Ancak @new olarak bildirildiği için bu değişken yalnızca 128 karakter barındırabilir. içinde bazı tek tırnak işaretlerini @newgeçirerek bunun üstesinden gelebiliriz.
CREATE PROCEDURE sp_MySetPassword
@loginname SYSNAME,
@old SYSNAME,
@new SYSNAME
AS
-- Declare variable.
DECLARE @command VARCHAR(200)
-- Construct the dynamic Transact-SQL.
SET @command = 'UPDATE Users SET password=' + QUOTENAME(@new, '''')
+ ' WHERE username=' + QUOTENAME(@loginname, '''')
+ ' AND password=' + QUOTENAME(@old, '''')
-- Execute the command.
EXEC (@command);
GO
Bir saldırgan 128 karakterlik bir arabelleğe 154 karakter geçirirse, eski parolayı bilmeden, sa için yeni bir parola ayarlayabilir.
EXEC sp_MySetPassword 'sa',
'dummy',
'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012'''''''''''''''''''''''''''''''''''''''''''''''''''
Bu nedenle, bir komut değişkeni için büyük bir arabellek kullanmanız veya dinamik Transact-SQL'ı doğrudan EXECUTE deyimi içinde yürütmeniz gerekir.
QUOTENAME(@variable, '''') ve REPLACE() kullanıldığında kesme
tarafından QUOTENAME() döndürülen ve REPLACE() dizeleri, ayrılan alanı aşarsa sessizce kesilir. Aşağıdaki örnekte oluşturulan saklı yordam neler olabileceğini gösterir.
Bu örnekte, @login, @oldpassword ve @newpassword arabellek boyutu yalnızca 128 karakterdir, ancak QUOTENAME() en fazla 258 karakter döndürebileceği için geçici değişkenlerde depolanan veriler kesilir.
@new 128 karakter içeriyorsa, @newpassword123... nolabilir; burada n 127. karakterdir. tarafından QUOTENAME() döndürülen dize kesildiğinden, aşağıdaki deyim gibi görünmesini sağlayabilirsiniz:
UPDATE Users SET password ='1234...[127] WHERE username=' -- other stuff here
CREATE PROCEDURE sp_MySetPassword
@loginname SYSNAME,
@old SYSNAME,
@new SYSNAME
AS
-- Declare variables.
DECLARE @login SYSNAME;
DECLARE @newpassword SYSNAME;
DECLARE @oldpassword SYSNAME;
DECLARE @command VARCHAR(2000);
SET @login = QUOTENAME(@loginname, '''');
SET @oldpassword = QUOTENAME(@old, '''');
SET @newpassword = QUOTENAME(@new, '''');
-- Construct the dynamic Transact-SQL.
SET @command = 'UPDATE Users set password = ' + @newpassword
+ ' WHERE username = ' + @login
+ ' AND password = ' + @oldpassword;
-- Execute the command.
EXEC (@command);
GO
Bu nedenle, aşağıdaki deyim tüm kullanıcıların parolalarını önceki kodda geçirilen değere ayarlar.
EXEC sp_MyProc '--', 'dummy', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678'
Kullanırken REPLACE() ayrılan arabellek alanını aşarak dize kesilmesini zorlayabilirsiniz. Aşağıdaki örnekte oluşturulan saklı yordam neler olabileceğini gösterir.
Bu örnekte, @login, @oldpassword, ve @newpassword için ayrılan arabellekler yalnızca 128 karakter barındırabilecek şekilde tahsis edilmiştir, ancak QUOTENAME() en fazla 258 karakter döndürebildiği için veriler kesilmekte. 128 karakter içeriyorsa @new , @newpassword olabilir '123...n'; burada n 127. karakterdir. tarafından QUOTENAME() döndürülen dize kesildiğinden, aşağıdaki deyim gibi görünmesini sağlayabilirsiniz:
UPDATE Users SET password='1234...[127] WHERE username=' -- other stuff here
CREATE PROCEDURE sp_MySetPassword
@loginname SYSNAME,
@old SYSNAME,
@new SYSNAME
AS
-- Declare variables.
DECLARE @login SYSNAME;
DECLARE @newpassword SYSNAME;
DECLARE @oldpassword SYSNAME;
DECLARE @command VARCHAR(2000);
SET @login = REPLACE(@loginname, '''', '''''');
SET @oldpassword = REPLACE(@old, '''', '''''');
SET @newpassword = REPLACE(@new, '''', '''''');
-- Construct the dynamic Transact-SQL.
SET @command = 'UPDATE Users SET password = '''
+ @newpassword + ''' WHERE username = '''
+ @login + ''' AND password = ''' + @oldpassword + '''';
-- Execute the command.
EXEC (@command);
GO
QUOTENAME() ile olduğu gibi, REPLACE() tarafından dize kısaltılması, tüm durumlar için yeterince büyük olan geçici değişkenler belirlenerek önlenebilir. Mümkün olduğunda, dinamik Transact-SQL'in içinde doğrudan QUOTENAME() veya REPLACE() çağırmalısınız. Alternatif olarak, gerekli arabellek boyutunu aşağıdaki gibi hesaplayabilirsiniz.
@outbuffer = QUOTENAME(@input) için belirtilen boyut @outbuffer, 2 * (len(@input) + 1) olmalıdır. Önceki örnekte olduğu gibi REPLACE() ve çift tırnak işaretlerini kullandığınızda, bir 2 * len(@input) arabelleği yeterlidir.
Aşağıdaki hesaplama tüm durumları kapsar:
WHILE LEN(@find_string) > 0, required buffer size =
ROUND(LEN(@input) / LEN(@find_string), 0)
* LEN(@new_string) + (LEN(@input) % LEN(@find_string))
QUOTENAME(@variable, ']') kullanıldığında kesme
Veritabanı motoru güvenilir bir nesnenin adı, QUOTENAME(@variable, ']') biçimini kullanan deyimlere geçirildiğinde kesme işlemi meydana gelebilir. Aşağıdaki örnekte bu senaryo gösterilmektedir.
Bu örnekte, @objectname 2 * 258 + 1 karaktere izin verilmelidir.
CREATE PROCEDURE sp_MyProc
@schemaname SYSNAME,
@tablename SYSNAME
AS
-- Declare a variable as sysname. The variable will be 128 characters.
DECLARE @objectname SYSNAME;
SET @objectname = QUOTENAME(@schemaname) + '.' + QUOTENAME(@tablename);
-- Do some operations.
GO
Sysname türündeki değerleri birleştirirken, değer başına en fazla 128 karakteri barındıracak kadar büyük geçici değişkenler kullanmanız gerekir. Mümkünse QUOTENAME()'yi doğrudan dinamik Transact-SQL içinde çağırın. Aksi takdirde, önceki bölümde açıklandığı gibi gerekli arabellek boyutunu hesaplayabilirsiniz.