Open Web Application Security Project (OWASP) Nedir?

Açık Web Uygulaması Güvenlik Projesi, web uygulama güvenliği ile ilgili makaleler, dökümanlar, araçlar üreten kâr amacı gütmeyen bir topluluktur.
OWASP TOP 10
OWASP, belirli yıllarda web güvenliği ile alakalı bilgiler toplayarak, o yıla ait TOP 10 güvenlik zaafiyetini sitelerinde yayınlıyorlar.
Bizde şuan OWASP ASP.NET TOP 10 2017 yılında çıkan son halindeki maddeleri inceleyeceğiz.
A1 Injection
- SQL Injection
UYGULA: SQL Injection zaafiyetini önlemek için, Entity Framework gibi bir object relational mapper (ORM) kullan veya t-sql komutlarını stored procedureler ile çalıştır.
UYGULA: Projemizde dinamik veya direkt SQL sorguları oluşturmak yerine, SQLParameter kullanarak sql injection saldırılarını önleyebilirsin.
Örnek:
public void OnGet(string userId)
{
string connectionString = "Server=(local);Database=SqlInjectionTest;Trusted_Connection=True;";
string queryString = "SELECT * FROM Users WHERE Id = @UserId";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("@UserId", "Ali");
try
{
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("\t{0}\t{1}\t{2}",
reader[0], reader[1], reader[2]);
}
reader.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
YANLIŞ: Dinamik T-SQL metinlerini, projenin içerisinde kullanmak.
Örnek:
public void OnGet(string userId)
{
string connectionString = "Server=(local);Database=SqlInjectionTest;Trusted_Connection=True;";
string queryString = "SELECT * FROM Users WHERE Id = " + userId;
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
try
{
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("\t{0}\t{1}\t{2}",
reader[0], reader[1], reader[2]);
}
reader.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
http://www.ayazduru.com.tr/users?userId=1; DROP ALL TABLES; –** adresine istek yaptığımızda, veritabanındaki bütün tabloları silecektir. Bu açık sayesinde veritabanımıza gelen bütün sorgular çalışacaktır.
UYGULA: Veritabanı bağlanmak için kullandığın kullanıcının yetkilerini yapacağı iş kadar ayarla. sa (system administrator) kullanıcısı gibi bütün yetkilere sahip kullanıcılar ile bağlanma.
- Operating System Injection
UYGULA: System.Diagnostics.Process.Start ile belirli komutların çalışmasını sağla.
Örnek:
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = "validatedCommand";
startInfo.Arguments = "validatedArg1 validatedArg2 validatedArg3";
process.StartInfo = startInfo;
process.Start();
UYGULA: Kullanıcıdan gelen bütün değerlerin format kontrolünü yapın.
//Kullanıcıdan gelen değer
string ipAddress = "127.0.0.1";
//Ip adresi değerini boş olup, olmadığını kontrol etme
if (!string.IsNullOrEmpty(ipAddress))
{
// Ip adresi formatını kontrol etme
if (IPAddress.TryParse(ipAddress, out var address))
{
return address.ToString();
}
else
{
//Verilen formata uygun değilse hata ekranına yönlendir.
}
- LDAP Injection
UYGULA: LDAP sorgularında özel karakterleri escape edip, çalıştır.
https://www.nuget.org/packages/AntiXss paketini yükledikten sonra;
string encodedId = Microsoft.Security.Application.Encoder.LdapFilterEncode(id);
DirectorySearcher search = new DirectorySearcher(new DirectoryEntry());
search.Filter = "(&(objectClass=user)(employeeid=" + encodedId + "))";
search.PropertiesToLoad.Add("mail");
search.PropertiesToLoad.Add("telephonenumber");
SearchResult sresult = search.FindOne();
A2 Broken Authentication
UYGULA: ASP.NET Identity framework paketini kullan. Her kullanıcıya farklı PBKDF2 hashleme ve SecurityStamp gibi güvenlik önlemlerinden yararlanabilirsiniz.
UYGULA: Güvenli parola politikası oluştur. 6 ayda bir parola yenileme, Büyük harf, Küçük harf özel karakter zorunluluğu gibi.
Örnek: ASP.NET Identity Konfigürasyonu
services.Configure<IdentityOptions>(options =>
{
//Parola Ayarları
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequireLowercase = true;
options.Password.RequiredUniqueChars = 6;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 3;
options.SignIn.RequireConfirmedEmail = true;
options.User.RequireUniqueEmail = true;
});
UYGULA: Çerez politikası belirle. Belirli bir süre içerisinde oturuma kapatmak gibi.
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.Expiration = TimeSpan.FromHours(1)
options.SlidingExpiration = true;
});
A3 Sensitive Data Exposure
YANLIŞ: Veritabanında ki parolaları şifreleme teknikleri ile kullanmak.
Tersine mühendislik ile kırılabilir. Ayrıca kullanıcı gizliliğine karşıdır. Kullanıcının parolalarını aynı şifreleme tekniği ile bir başkası çözebilir.
UYGULA: Güçlü hashleme yöntemleriyle parolaları sakla.
UYGULA: Parolalarda dictionary saldırısı gibi saldırıları önlemek için, Büyük harf, Küçük Harf, Özel karakter girilmesini zorunlu kıl.
UYGULA: TLS 1.2 protokülünü kullan. LetsEncrypt.org ile ücretsiz sertifika alabilirsin.
UYGULA: Sunucuda SSL gibi eski protokol ve şifreleme tekniklerini devre dışı bırak. IISCrypto ve https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/manage-ssl-protocols-in-ad-fs sayfalarını inceleyebilirsiniz.
UYGULA: Security Headers ile web uygulama güvenliği için tarayıcıyı özelleştir.
ASP.NET Security Headers ve Samesite Cookie blog yazımı veya StripHeaders, SCOTT HANSELMAN ASP.NET Security Headers, SecurityEssentials sayfalarını inceleyebilirsiniz.
Örnek IIS Web.config:
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Strict-Transport-Security" value="max-age=31536000"/>
<add name="X-Content-Type-Options" value="nosniff"/>
<add name="X-Xss-Protection" value="1; mode=block"/>
<add name="X-Frame-Options" value="SAMEORIGIN"/>
<add name="Content-Security-Policy" value="default-src https:; img-src * 'self' data: https:; style-src 'self' 'unsafe-inline' www.google.com platform.twitter.com cdn.syndication.twimg.com fonts.googleapis.com; script-src 'self' 'unsafe-inline' 'unsafe-eval' www.google.com cse.google.com cdn.syndication.twimg.com platform.twitter.com platform.instagram.com www.instagram.com cdn1.developermedia.com cdn2.developermedia.com apis.google.com www.googletagservices.com adservice.google.com securepubads.g.doubleclick.net ajax.aspnetcdn.com ssl.google-analytics.com az416426.vo.msecnd.net/;"/>
<add name="Referrer-Policy" value="no-referrer-when-downgrade"/>
<add name="Feature-Policy" value="geolocation 'none';midi 'none';notifications 'none';push 'none';sync-xhr 'none';microphone 'none';camera 'none';magnetometer 'none';gyroscope 'none';speaker 'self';vibrate 'none';fullscreen 'self';payment 'none';"/>
<remove name="X-Powered-By" />
<remove name="X-AspNet-Version" />
<remove name="Server" />
</customHeaders>
</httpProtocol>
...
A4 XML External Entities (XXE)
XXE (XML External Entity) Güvenlik Zafiyeti xml verisini parse ederken, özel olarak çağrılmış bir entity (varlık) çağrılması sonucu çalışır.
Önlemek İçin Örnek:
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
XmlReader reader = XmlReader.Create(streamReader, settings);
System.Xml.XmlDocument gelen = new System.Xml.XmlDocument();
gelen.Load(reader);
settings.DtdProcessing = DtdProcessing.Prohibit; ile önleyebiliriz.
A5 Broken Access Control
Weak Account management
Çerezlerin httpOnly aracılığıyla gönderildiğinden emin olun:
CookieHttpOnly = true,
ExpireTimeSpan ve SlidingExpiration süresini ayarlayarak gerekli önlemleri alabilirsin:
ExpireTimeSpan = TimeSpan.FromMinutes(60),
SlidingExpiration = false
Çerezin Production (Canlı) ortamda https üzerinde gönderilmesini sağlayabilirsin.
<httpCookies requireSSL="true" xdt:Transform="SetAttributes(requireSSL)"/>
<authentication>
<forms requireSSL="true" xdt:Transform="SetAttributes(requireSSL)"/>
</authentication>
Giriş Yap, Kayıt Ol, Parola Sıfırlama gibi metotlarda brute force saldırılarını önlemek için düzenlemeler yapın. Ayrıca bir Captcha sistemi kullanabilirsiniz. reCAPTCHA gibi.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[AllowXRequestsEveryXSecondsAttribute(Name = "LogOn",
Message = "You have performed this action more than {x} times in the last {n} seconds.",
Requests = 3, Seconds = 60)]
public async Task<ActionResult> LogOn(LogOnViewModel model, string returnUrl)
YANLIŞ: Kendi yazdığınız kimlik doğrulama ve session management sistemlerini kullanmak. Bunun yerine .Net ile uzun zamandır geliştirilmiş yapıları kullanın.
YANLIŞ: Giriş Yaptıktan sonra kullanıcıya "Email adresiniz yanlış" veya "Şifreniz yanlış" gibi bilgiler vermek.
"Başarısız giriş denemesi" gibi daha genel bilgiler vererek kötü niyetli insanların bilgi edinmesini önleyebilirsin.
Missing function-level access control
UYGULA: Action veya Handler metotlarınızı yetkili girişe, role veya policy'e göre kısıtlayın.
[Authorize(Roles = "Admin", Policy="AtLeast21Age")]
[HttpGet]
public ActionResult Index(int page = 1)
Insecure Direct object references
Gelen verilerin, var olup olmadığına, başka kullanıcının verilerini değiştirmediğini kontrol etmeliyiz. Burada primary key veri tipi olarak Guid gibi benzersiz bir veri tipi kullanarak bu verilerin daha zor bulunmasını sağlayabiliriz. Integer gibi ardışık veriler ile daha kolay deneme yapılacaktır.
// Güvensiz, gelen id başka bir kullanıcıya ait olsada çalışacaktır.
public ActionResult Edit(Guid id)
{
var user = _context.Users.FirstOrDefault(e => e.Id == id);
return View("Details", new UserViewModel(user);
}
// Güvenli, gelen id kullanıcıya ait mi kontrol ediliyor
public ActionResult Edit(Guid id)
{
var user = _context.Users.FirstOrDefault(e => e.Id == id);
if (user.Id != _userIdentity.GetUserId())
{
return View("Error", error);
}
return View("Edit", new UserViewModel(user);
}
A6 Security Misconfiguration
Debug and Stack Trace
Production ortamında hata sayfalarının gösterilmesini kapatmalıyız.
#if DEBUG
if (env.IsDevelopment() || HostingEnvironment.IsEnvironment("Local"))
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
#else
app.UseHsts();
app.UseSecurityHeader();
#endif
YANLIŞ: Varsayılan kullanıcı parolaları basit yapmak. Canlı ortamda bu şifreler rahatlıkla kırılabilir.
UYGULA: Web API projelerini sadece https protokülüyle yayınla. (bknz: Downgrade attack) Web projelerinde http, https protokollerini kullanabilirsin ancak httpden https'e yönlendir.
app.UseHttpsRedirection();
Cross-site request forgery
YANLIŞ: Hassas verileri Anti-Forgery-Tokens kullanmadan gönder.
UYGULA: Hassas verileri POST/PUT ile Anti-Forgery-Tokens kullanarak göndermeliyiz. Burada amaç bu token oluşmadan yani get isteği olmadan post/put yapmayı önlemektir.
<form method="post" asp-antiforgery="true">
...
</form>
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery antiforgeryProvider
$.ajax(
{
type: "POST",
url: '@Url.Action("Action", "Controller")',
contentType: "application/x-www-form-urlencoded; charset=utf-8",
data: {
id: id,
'__RequestVerificationToken': '@antiforgeryProvider.GetAndStoreTokens(this.Context).RequestToken'
}
})
A7 Cross-Site Scripting (XSS)
YANLIŞ: Kullanıcıdan gelen her değeri kabul et. HTML, JavaScript, CSS, LDAP gibi değerleri encode edilmiş şekilde almalıyız.
YANLIŞ: [AllowHTML] özelliğini @Html.Raw metotunu kullan. XSS-Protection yazımı inceleyebilirsiniz.
UYGULA: İsteklere verilen cevaplara Content Security Policy headerını ekle.
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Content-Security-Policy"
value="default-src 'none'; style-src 'self'; img-src 'self';
font-src 'self'; script-src 'self'" />
A8 Insecure Deserialization
Deserialization can be dangerous Buradaki yazıyı inceleyebilirsiniz.
YANLIŞ: Güvenilmeyen kaynaklardan serialized objectler kabul etmek.
UYGULA: Kötü niyetli kişiler cookielerdeki serileştirilmiş oturum bilgilerini değiştirebilir. ters serileştirdiğimizde bu bilgilerin o kullanıcıya ait olup olmadığını kontrol etmeliyiz.
UYGULA: Domain Objectlerine deserilization(ters serileştirme) yapılmasını önlemeliyiz.
UYGULA: Ters serileştirdiğimiz kodları kullanırken sınırılı erişim yetkileriyle çalıştırmalıyız.
A9 Using Components with Known Vulnerabilities
UYGULA: .NET framework sürümlerini güncelle.
UYGULA: Nuget paketlerinin güncel sürümlerini kullan.
UYGULA: OWASP Dependency-Check aracını kullan.
A10 Insufficient Logging & Monitoring
UYGULA: Bütün oturum açma, erişim hataları, sunucu tarafındaki doğrulama hataları, şüpheli veya tehlikeli olabilecek kullanıcıları algılamak için buralardaki işlemleri log günlüğüne kaydet.
UYGULA: Şüpheli faaliyetlerin tespit edilmesi ve zamanında yanıtlanması için etkili izleme ve uyarılar oluşturun.
YANLIŞ: Hata mesajlarını genel bir yazı ile günlüğe kaydetmek. _logger.LogInformation("Hata alındı."); gibi.
Bunun yerine yığın izlemeyi, hata mesajını ve hataya neden olan kullanıcı kimliğini günlüğe kaydedin.
YANLIŞ: Kullanıcı parolası gibi hassas verileri günlüğe kaydetmek.
Logging
Startup.cs dosyasına bazı eklemeler yaparak bütün hataları yakalabiliriz.
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
var errorFeature = context.Features.Get<IExceptionHandlerFeature>();
var exception = errorFeature.Error;
Log.Error(String.Format("Stacktrace of error: {0}",exception.StackTrace.ToString()));
});
});
Dependency injection ile razor ve controller sayfalarımızda loglama yapabiliriz.
public class AboutModel : PageModel
{
private readonly ILogger _logger;
public AboutModel(ILogger<AboutModel> logger)
{
_logger = logger;
}
public string Message { get; set; }
public void OnGet()
{
Message = $"About page visited at {DateTime.UtcNow.ToLongTimeString()}";
_logger.LogInformation(Message);
}
}
Monitoring
Monitoring, çalışan bir sistemin performansını, sağlığını temel performans göstergeleri aracılığıyla takip etmemize olanak tanır.
ASP.NET Elasticsearch, Kibana, Serilog ile Loglama yazımı okuyabilirsiniz.
Microsoft Github Reposu Observability linkinden, Logging ve Monitoring hakkında detaylı bilgiler edinebilirsiniz.
[BONUS] A10 Unvalidated redirects and forwards (OWASP 2013 TOP 10)
Güvenilmeyen url adreslerine yönlendirmeyi önlemek için;
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return Page();
}
}
return Page();
}
return LocalRedirect(returnUrl); metotununu kullanabiliriz.
Diğer Tavsiyeler
HTTP Strict Transport Security diğer adıyla HSTS, internet tarayıcıların gelen her istekte HTTPS'e yönlendirerek, downgrade saldırılarını önlemeye yarar.
app.UseHsts();
ile kullanabiliriz.
Third-Party Code Security and Quality (Üçüncü parti Kod Güvenlik ve Kalitesi)
Kullandığımız 3. parti kütüphane, paket, kod, framework içerisindeki zaafiyetler doğrudan bizi de etkileyebilir. Bunu önlemek için 3. parti kodları incelememiz ve test etmemiz gerekir.
Code Tampering (Kod Kurcalama)
Web uygulamalarının compile edilmiş halini on-premise olarak başka firmalara veriyorsak, yazdığımız kodların kurcalanmasını önlemek için bir obfuscator aracı kullanmamız gerek. Obfuscator dediğimiz araçlar, decompile edilmiş kodların anlaşılabilirliği daha zor hale getiren, yani obfuscate (bulanıklaştırma) işlemini yapan araçlardır.
ASP.NET uyumlu obfuscator olan, Dotfuscator aracını inceleyebilirsiniz.
Reverse Engineering (Tersine Mühendislik)
Bir makinenin nasıl çalıştığını anlamak için, parçalarını sökeriz ve bu parçaların nasıl çalıştığına bakarız. Aynı şekilde yazılım alanında compile edilmiş kodları, decompile ederek bütün kodu görebiliriz. Ayrıca bir web uygulamasında bu işe hangi teknolojinin kullanıldığını, hangi frameworklerin kullanıldığını öğrenerek başlayabiliriz.
Örnek olarak IIS veya Kestrel Response'ların Server Header'ına kullandığımız teknoloji hakkında karşı tarafa bilgi vermektedir. Bunu şu şekilde önleyebiliriz.
IIS Kullanıyorsak;
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
...
<remove name="X-Powered-By" />
<remove name="X-AspNet-Version" />
<remove name="Server" />
</customHeaders>
</httpProtocol>
Kestrel Kullanıyorsak;
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>()
.ConfigureKestrel((context, options) => {
options.AddServerHeader = false;
});
});
}
Görüşmek dileğiyle, kendinizi iyi bakın..