20 Şubat 2021 Cumartesi

İki Aşamalı OAuth

  İki aşamalı OAuth kimlik bilgilerini sunucuya şu yollarla sağlanan istemciye benzer. Yetkilendirme dahil olmadan temel veya özet kimlik doğrulamasını kullanan yetkilendirme başlığı ile.

OAuth spesifikasyonu bu kimlik doğrulama stilini belirtmediğini ancak sunucuya bir istemcinin kimlik doğrulamak için yaygın olarak kullanılır.

iki aşamalı OAuth aşağıdaki adımları içerir.

1-İstemci sunucudan bir anahtar ve  dışarıdan bir gizli anahtar ister. Anahtar müşteri için bir tanımlayıcıdır. Gizli anahtar ise; istemci ve sunucu arasında paylaşılan bir gizli anahtardır.

2-İstemci korunan bir kaynağa erişim talebinde bulunurken anahtar ve imzalama yönetimi ve işareti içeren yetkilendirme başlığına nature, timestamp, nonce isteğe bağlı olarak OAuth protokol sürümünü ekler.

Sunucu kaynağa erişim izni vermeden önce imzayı doğrular. Bu yaklaşım kimlik doğrulama akışında yalnızca iki taraf olduğu için iki ayaklı olarak adlandırılır. Sunucu istemcinin kimliğini doğrulaması gerektiğinde iki aşamalı OAuth kullanır. ( Erişim kontrolü, Günlük kaydı, ölçüm, hız sınırlama v.b )

İki aşamalı OAuth korumalı erişim sağlayan bir kaç istemcinin bulunduğu durumlar için uygundur. Sunucu her istemciye bir anahtar ve gizli anahtar verebilir. Müşteriyi bir imza com-OAuth göre  yerleştirilir. İki aşamalı OAuth aynı zamanda üç aşamalı OAuth destekler.

Örneğin; Bir müşterinin bir çalışanı işe alma sürecini uygulamak için sunucuyla etkileşime girer. İstemci son kullanıcılarının kimliğini doğrulamak için kendi kimlik doğrulama mekanizmasına sahiptir. Müşteri  kimlik doğrulamak için tanımlama bilgilerini web tabanlı bir uygulamaya girebilir. Sunucu istemcinin kimlik doğrulaması için iki aşamalı OAuth kullanması gerektiğinden her istekte bir sunucuya  Sunucunun atadığı varsayılan a1191fd420e0164c2f9aeac32ed35d23 oauth_consumer_key ve müşteri gizli anahtarı fd9b9d0f769c3bcc548496e4b5077da79c02d7be imza gönderir.  

Müşterinin yeni bir kaynak oluşturmak için aday bilgilerinin gönderdiğini varsayalım ve kimliği doğrulanmış bir istekte bulunmak için istemcinin bir yetkilendirme başlığı eklemesi gerekir.

oauth_signature parametresinin değeri sonuç olarak müşterinin daha sonra yetkilendirme başlığını takip eder ve istekte bulunur.


# Request to enter candidate info

POST /hires HTTP/1.1

Host: www.example.org

Authorization: OAuth realm="http://www.example.com/hires",

                               oauth_consumer_key=a1191fd420e0164c2f9aeac32ed35d23,

                               oauth_nonce=85a55859fde262ba,

                               oauth_signature=d8e19bb988110380a72f6dba33b2ba5903272fe1,

                               oauth_signature_method=HMAC-SHA1,

                               oauth_timestamp=1258308689,

                               oauth_version=1.0

Content-Type: application/json

{

   "name": "Joe Prospect",

   ...

}

# Response

HTTP/1.1 201 Created

Location: http://www.example.org/hires/099

Content-Location: http://www.example.org/hires/099

Content-Type: application/json

{

   "name": "Joe Prospect",

   "id": "urn:example:hr:hiring:099",

   ...

   "link" : {

      "rel" : "http://www.example.org/rels/hiring/post-ref-result",

      "href" : "http://www.example.org/hires/099/refs"

   }

}

POST /hires HTTP/1.1 > korumalı bir kaynağa erişim isteği;

Authorization: OAuth realm="http://www.example.com/hires",
oauth_consumer_key=a1191fd420e0164c2f9aeac32ed35d23,
oauth_nonce=85a55859fde262ba,
oauth_signature=d8e19bb988110380a72f6dba33b2ba5903272fe1,
oauth_signature_method=HMAC-SHA1,
oauth_timestamp=1258308689,
oauth_version=1.0
> Tüketici anahtarı ve tüketici gizli anahtarı (imza) kullanılarak hesaplanan yetkilendirme başlığı;
 
OAuth; istemcilerin kimlik bilgilerini sorgu parametreleri aracılığıyla sağlanmasına da izin verdiğini unutmayalım.  

# Request to enter candidate info
POST /hires?oauth_consumer_key=a1191fd420e0164c2f9aeac32ed35d23&
                  oauth_nonce=85a55859fde262ba&
                  oauth_signature=d8e19bb988110380a72f6dba33b2ba5903272fe1&
                  oauth_signature_method=HMAC-SHA1&
                  oauth_timestamp=1258308689&oauth_version=1.0 HTTP/1.1

Host: www.example.org
Content-Type: application/json
{

   "name": "Joe Prospect",
   ...
}

Ancak; Yetkilendirme üstbilgisinin kullanılması URI çoğalmasını azaltır.

İstemci geçerli bir Yetkilendirme üstbilgisini ekleyemezse; sunucu WWW-Authenticate başlığı ve 401 (Yetkisiz) yanıt başlığı cevabı döner.

# Request to enter candidate info
POST /hires HTTP/1.1
Host: www.example.org
Content-Type: application/json
{

   "name": "Joe Prospect",
   ...
}


# Response
401 Unauthorized
WWW-Authenticate: OAuth realm="http://www.example.com/hires"
Content-Type: text/html;charset=UTF-8
<html>
   ...
   <body>

      <p>Unauthorized.</p>
   </body>
</html>

Bu işlem sunucunun kimlik doğrulama için OAuth kullandığını gösterir.

13 Şubat 2021 Cumartesi

İstemcilerin Kimlik Doğrulamasında Temel Kimlik Doğrulama Kullanımı

 

  İstemcide, müşteri tanımlayıcısının birleştirilmesi kullanıcı adı ve paylaşılan şifre <identifier>:<secret> ardından bu metinin Base64 kodlamasını dahil etmeniz gerekir. İstemci isteklerinde bir metin başlığı ortaya çıkaran metin değeri : Authorization: Basic <Base64 encoded value>

Sunucuda metnin kodunu çözün ve şifrenin aynı olduğunu doğrulayın. İstemci sunucunun bir kaynak için temel kimlik doğrulaması gerektiğini önceden biliyorsa her istek geldiğinde yetkilendirme üst bilgisi içerilebilir. 401 alınması önlenebilir.

iki kişi için temel ve özet kimlik doğrulama gibi kimlik doğrulama şemaları kullanılabilir.

Senaryolar: Bir müşteri korunan bir kaynağa kendi adına eriştiğinde ve bir müşteri bir kullanıcı adına korumalı bir kaynağa erişiyorsa.

İstemcide güvenli bir şekilde saklanmadıkça hiç bir sır gerçekte güvenli değildir.


Temel kimlik doğrulama; HTTP 1.0'a kadar uzanır ve daha sonra RFC 2617 tarafından belirtilir. Temel kimlik doğrulamasında istemci Base 64 paylaşılan şifre kodlar ve bunu Yetkilendirme isteği başlığı ile destekler.

Base64 kodlaması tersine çevrilebilir. Aşağıdaki durumlarda temel kimlik doğrulaması kullanmayın. Sunucuya bağlanmak için TLS kullanmaz.


Aşağıdaki kodda bir kaynağa erişmeye çalışan bir istemcinin ilk isteğine yer verilmiş.


# Request

GET /photos HTTP/1.1

Host: www.example.org


# Response

401 Unauthorized

WWW-Authenticate: Basic realm="Photos App"

Content-Type: application/xml;charset=UTF-8


<error xmlns:atom="http://www.w3.org/2005/Atom">

   <message>Unauthorized.</message>

</error>

# Request
GET /photos HTTP/1.1 > Kimlik bilgileri olmayan bir istek

# Response

401 Unauthorized

WWW-Authenticate: Basic realm="Photos App" > Temel kimlik doğrulaması kullanarak kimlik bilgilerini sağlamayı zorlayan yanıt.

Kaynak korunduğundan, sunucu istemcinin kimlik bilgilerini sağlamasını ister. Basic adlı bir kimlik doğrulama şeması kullanarak, gerçek değeri opak dizedir. Sunucuda korunan bir alanı tanımlar.

İstemcinin / kullanıcının paylaşılan gizli değeri ile photoapp.001 olarak tanımlandığını varsaydığımızda basicauth. istemci photoapp.001. dizesinin Base64 kodlamasını hesaplar.  Cauth ve Yetkilendirme başlığıyla aşağıdaki isteği gönderir.

# Request

GET /photos HTTP/1.1

Host: www.example.org

Authorization: Basic cGhvdG9hcHAuMDAxOmJhc2ljYXV0aA==

# Response

HTTP/1.1 200 OK

Content-Type: application/xml;charset-UTF8

Authorization: Basic cGhvdG9hcHAuMDAxOmJhc2ljYXV0aA== > Sunucu kimlik bilgilerini Base64 kullanarak çözer yöneticinin, istemcinin kattığı sunucu tarafından bilinenle eşleşir ve istemciye izin verilir. Sunucu alınan istekte bir istek daha alırsa yada yetkilendirme başlığı yoksa veya sağlanan yetkilendirme başlığındaki bilgiler ile eşleşmiyorsa sunucu WWW-Authentication hatasını döndürür.

Kimliği doğrulanmış yanıtlar hassas bilgiler içerdiğinden Cache-Control ve Expires üst bilgileri yanıtı için uygundur.
Örneğin; Yanıt istemciye özeldir, paylaşmayı önlemek için Cache-Control :private kullanın. Yanıtı saklamaktan veya diğer istemcilere sunmakta için gelen önbelleklerde kullanılır.

# Request
GET /users/admin HTTP/1.1
Host: www.example.org
Authorization: Basic cGhvdG9hcHAuMDAxOmJhc2ljYXV0aA==
# Response
HTTP/1.1 200 OK
Cache-Control: max-age:3600,private
Vary: Authorization
Content-Type: application/xml;charset-UTF8

Yetkilendirme Başlığını Genişletme

Özet Kimlik Doğrulaması ve OAuth kimlik bilgilerini sunucuya göndermek için bu başlık kullanılır. Örneği Amazonun Basit Deploma Hizmeti (s3)bu başlığı kullanarak istemciler aşağıdaki istek başlığı kullanarak sunucuya kimlik doğrulaması yapar.

Authorization: AWS AWSAccessKeyId:Signature

Burada AWS Amazon tarafından kullanılan kimlik doğrulama şeması için tanımlayıcıdır.  Amazon aynı verilerin imzasını hesaplayarak istemcinin kimliğini doğrular.


7 Şubat 2021 Pazar

İstemcilerin Kimlik Doğrulamasında Özet Kimlik Doğrulama

 Temel kimlik doğrulamaya benzer istemcinin kimlik bilgilerinin özetini sunucuya göndermesi dışında yeniden kimlik gönderim saldırılarını önlemek için mekanizmaları sağlar.

İstemci erişim için bir Yetkilendirme başlığı eklemeden bir istek gönderdiğinde korumalı kaynak dönüş kodu olarak 401 ile birlikte özet kimlik doğrulama şemasında bilgiler alır. Bu bilgiler bir kez yada sınırlı sayıda alınabilen bilgilerdir.

Sağlanan özetin içerisinde depolanan kimlik bilgilerinin bir özetiyle eşleştiğini doğruladıktan sonra Authentication-Info başlığı ekleyin. Bu bilgi sunucu tarafında eşdeğerdir.

İstemciler genel olarak özeti hesaplamak için MD5 kullanır. Temel kimlik doğrulamasından farklı olarak bu teknik şifrelenmemiş bir paylaşılan sırrı değiş tokuş etmez.


# Request

GET /photos HTTP/1.1

Host: www.example.org

# Response

401 Unauthorized

WWW-Authenticate: Digest realm="Sample app", nonce="6cf093043215da528d7b5039ed4694d3",

         qop="auth"

Content-Type: application/xml;charset=UTF-8

<error xmlns:atom="http://www.w3.org/2005/Atom">

   <message>Unauthorized.</message>

</error>

# Request

GET /photos HTTP/1.1

Host: www.example.org

Authorization: Digest username="photoapp.001", realm="Sample app",

nonce="6cf093043215da528d7b5039ed4694d3",
         uri="/photos", response="89fba5bf5e5f9dd69865258c21860956",
         cnonce="c019e396409afe784ae9f203b8dfdf7e", nc=00000001, qop="auth"
# Response
HTTP/1.1 200 OK
Content-Type: application/xml;charset-UTF8

GET /photos HTTP/1.1   > kimlik bilgisi olmayan bir istek;

# Response

401 Unauthorized

WWW-Authenticate: Digest realm="Sample app", nonce="6cf093043215da528d7b5039ed4694d3",

qop="auth" > nonce içeren yanıt

cnonce="c019e396409afe784ae9f203b8dfdf7e", nc=00000001, qop="auth"  > Yanıt yönergesi içeren istek.

Temel kimlik doğrulamasından farklı olarak özet kimlik doğrulaması, istemcinin bir özet sağlaması gerekir.

realm : Sunucudaki korumalı alanı tanımlayan opak bir dize.

nonce: Her 401 Yetkisiz yanıtıyla benzersiz şekilde oluşturulan dize. Bir özet oluştururken bu değeri kullanmaları gerekir. Yeniden isteklerde kullanılan bazı değerlerden daha eski nonce yönergeleri kullanarak yapılan saldırıları içerir.

qop: Özet kimlik doğrulaması yönergeler için iki değer belirtir. Aut ve Auth-int. 

Auth:  Sunucunun istemci kimlik doğrulaması için özet kimlik doğrulaması kullandığını belirtir.

Auth-int: Sunucunun bu kimlik doğrulamasını aynı zamanda isteklerin bütünlüğü Qop = auth-int istemcilerin isteğinin gövdesine özeti hesaplarken ekler. 

*İstemci / Kullanıcı tanımlayıcısının, alanı ve paylaşılan gizli değer aşağıdaki şekilde birleştirin.  MD5 değerini hesaplayın. Değeri : A1 dir.
<identifier>:<realm>:<secret>

*İstek Yönetimini ve istek URL sini <method>:<URI> MD5 ekleyin. Sonucunun A2 olduğunu söyleyin.

*A1, nonce ve A2 yi <A1>:<nonce>:<A2> olarak birleştirin ve MD5 değerini hesaplayın.

Kullanıcı elde edilen değeri yanıt değeri olarak kullanır.

Nonce kullanımında; Sunucular tek seferlik veya sınırlı kullanımlı bir belirteç kullanarak saldırıların yeniden tekrarlanma olasılığını sınırlayabilir.

Tek seferlik veya sınırlı kullanılan biletler, requestlerde sunucunun kullanılan tüm belirteçlerinin günlüğünün tutulması gerekir.

WWW-Autheticate başlığı ayrıca domanin, opaque gibi diğer direktifleri içerebilir.

30 Ocak 2021 Cumartesi

Blok ve Bloklanan İşler

 İdeal olarak veritabanı uygulamanızın veritabanı kullanıcı sayısı ile doğrusal olarak ölçeklenmesi gerekir. Ancak kullanıcı sayısı arttıkça kullanıcı sayısı performansı düşürdüğü yaygın bir durumdur. Artan ölçekle ilişkili olan bozulmanın nedeni engellemedir.

SQL Serverda engellemenin temelleri;

*ACID özellikleri

*Veritabanı kilit ayrıntı düzeyi, yükseltme, modlar ve uyumluluk.

*ANSI izolasyon seviyeleri

*Dizinlerin kilitlenme üzerindeki etkisi

*Engellemeyi analiz etmek için gerekli bilgiler

*Engellemeyi önlemek için kararlar ve öneriler

*Engelleme algılama ve bilgi toplama süreçlerinin otomatikleştirme teknikleri,


Atomiklik, Tutarlılık, İzolasyon, Dayanıklılık.


USE AdventureWorks2012;
GO
IF (SELECT OBJECT_ID('dbo.ProductTest')

    ) IS NOT NULL
      DROP TABLE dbo.ProductTest;
GO
CREATE TABLE dbo.ProductTest (
ProductID INT CONSTRAINT ValueEqualsOne CHECK (ProductID = 1));
GO


--All ProductIDs are added into t1 as a logical unit of work
INSERT INTO dbo.ProductTest
          SELECT p.ProductID
          FROM Production.Product AS p;

GO
SELECT *
FROM dbo.ProductTest; --Returns 0 rows
SQL Server önceki INSERT deyimini mantıksal çalışma birimi olarak ele alır. Sütundaki CHECK kısıtı ProductTest tablosunun ProductID sinini yanlızca 1 değerine izin verir. Bu nedenle ProductTest tablosuna hiç bir kayıt eklemeyecektir. CHECK nedeniyle hata oluşacaktır. Bu SQL Server tarafından otomatik olarak sağlanır.


BEGIN TRAN

 --Start: Logical unit of work

--First:

INSERT INTO dbo.ProductTest

            SELECT p.ProductID

            FROM Production.Product AS p;

--Second:

INSERT INTO dbo.ProductTest

VALUES (1);

COMMIT --End: Logical unit of work

GO

SQL Serverda önceki ekleme görevinden birden çok INSERT çalıştığını düşünerek daha büyük bir işin çalıştığını düşünürsek;  yukarıdaki gibi daha büyük mantıksal çalışma birimi oluşacaktır. Önceki komut dosyası zaten oluşmuş olan ProductTest tablosu ile BEGIN TRAN ve COMMIT çifti ile tüm ifadelerin atomik olması gerektiğini öneren mantıksal çalışma birimini tanımlar. ilk INSERT ifadesi başarısız olacak oysa ikinci INSERT makuldur ve varsayılan davranış ikinci INSERT ifadesinden SQL Server yürütmesine izin verecektir.

Kullanıcı tanımlı işlemin atomikliği 2 yolla sağlanır.

* SET XACT_ABORT ON
* Explicit rollback


SET XACT_ABORT ON


SET XACT_ABORT ON deyimini kullanarak işlemin atomikliği değiştirilebilir.

SQL Server komuttaki bir işlemin başarısız olduğunda otomatik olarak geri dönüş yapıp yapmayacağının karar vermesini sağlar. INSERT ifadesindeki birinci aşamadaki işlem başarısız olursa otomatik olarak ikinci INSERT ifadesini yürütmeyecektir. SET XACT_ABORT bağlantı düzeyinde yenide yapılandırılıncaya kadar yada bağlantı kurulana kadar geçerli kalır. Varsayılan olarak bu özellik kapalıdır.


SET XACT_ABORT ON;
GO
BEGIN TRAN
 --Start: Logical unit of work
--First:
INSERT INTO dbo.ProductTest

            SELECT p.ProductID
            FROM Production.Product AS p;
--Second:
INSERT INTO dbo.ProductTest
VALUES (1);
COMMIT
 --End: Logical unit of work GO
SET XACT_ABORT OFF;
GO

Explicit rollback

TRY/CATCH hata yakalama mekanizmasını kullanarak kullanıcı tanımlı bir işlemin atomikliğini yönetebilirsiniz. SQL Server içerisinde TRY kod bloğu içinde ifade hata alırsa kodu CATCH bloğuna hatayı paslayarak tüm işlemler geri alınabilir ve sonraki ifadelerin yürütülmesi engellenebilir.


BEGIN TRY
      BEGIN TRAN
      --Start: Logical unit of work
      --First:
      INSERT INTO dbo.ProductTest

                  SELECT p.ProductID
                  FROM Production.Product AS p
      Second:
      INSERT INTO dbo.ProductTest
                  (ProductID)
      VALUES (1)
      COMMIT --End: Logical unit of work
END TRY
BEGIN CATCH
      ROLLBACK
      PRINT 'An error occurred'
      RETURN
END CATCH


23 Ocak 2021 Cumartesi

Kilit İçeriğini En Aza İndirgeme

 

  Kaynaklardan birinde kilit isteğinden kaçınarak kilitlenme çözülebilir. Kaynağa yanlızca veri okumak için erişilir. Bir kaynak üzerinde değişiklik yapmak her zaman özel bir kilit kazanacaktır. Kaynağın tutarlılığını korumak için kilitlenme durumunda kaynak erişimlerini tanımlanması gerekir. Salt okunur, kirli okuma özelliklerini kullanarak karşılıklı gelen kilit isteklerinden kaçınmaya çalışın.


Kaynak kilitlerinden kaçınmak için aşağıdaki tetikler kullanılır.

* Satır versiyonlama Uygulamak

* İzolasyon seviyesini arttırmak

* Kilitlenme ipuçlarının kullanılması.


Satır versiyonlama Uygulamak

Katı kilitlenme şeması kullanarak kaynaklara erişim engelleye çalışmak yerine READ_COMMITTED_SNAPSHOT izlosayon seviyesi veya SNAPSHOT izolasyon seviyesi ile satır versiyonlama. Satır versiyonlama izolasyon seviyelerini engellemeyi azaltmak için kullanılıyor. 


ALTER DATABASE AdventureWorks2012

SET READ_COMMITTED_SNAPSHOT ON;


Yukarıdaki T-SQL ile tempdb de bulunan satırların bir sürümüne sahip olabilirsiniz potansiyel olarak önceki kilitlenme senaryosundaki kilitlenmenin neden olduğu detayı görebilirsiniz. Bu okumalar farklı bir sürümde olduğu için kilit çekişmesine neden olmadan gerekli tüm okumalara izin verecektir. Satır sürümleme ek yük getirecektir. Özellikle tempdb de sorguda kullanılan tablo, dizinler. Artan değiş tokuş azaltılmış kilitlenmeler ve artan eşzamanlılık avantajına karşı ek yük ve maliyet değerlendirilebilir.


İzolasyon seviyesini arttırmak

Bazen bir SELECT ifadesi  tarafından istenen (S) kilidi dairesel engellemenin oluşumuna katkıda bulunacaktır.  SELECT deyimi içeren işlemin yalıtım düzeyini azaltarak bu tür döngüsel engellemelerden kaçınılabilir. SELECT ifadesindeki (s) kilidi istenmeden verilerin okunmasına ve böylece dairesel engellemelerden kaçınmasına yarar sağlayacaktır.  Ancak öngörülmeyen verilerin okunması kötü verileri döndürerek ciddi sorunlara sebep verecektir. 

Ayrıca bağlantıların kendilerini SERİLEŞTİRİLEBİLiR olarak ayarlayıp ayarlamadığını kontrol etmeniz gerekir. Bazen çevrimiçi bağlantı dizisi oluşturucuları bu seçeneği içerecek ve geliştiricilerinde bunu kullanması sonucunda istenmeyen sonuçlara yol açabilecektir. MSDTC varsayılan olarak serileştirilebilir kullanılır ancak bu değiştirilebilir.


Kilitlenme ipuçlarının kullanılması.

READ UNCOMMITTED izolasyon seviyesi gibi NOLOCK veya READUNCOMMITTED kilitlenme ipucu (s) kilitlerini önleyecektir. Belirli bir oturum tarafından istenir, böylece dairesel blokaj oluşumunu engeller.


Kilitleme ipucu etkisi sorgu düzeyindedir. Uygulandığı tablo ve dizinlerle sınırlıdır. NOLOCK ve  READUNCOMMITTED kilitlenme ipuçları yanlızca SELECT deyimlerinden ve veri seçim bölümlerinde izin verilir.

INSERT, DELETE, UPDATE

Kirli okuma sayfa bölümleri nedeniyle eksik veya fazla satırları içerebilir. Bu teknik sadece düşük kaliteli verilerin olduğu durumlarda kullanılabilir.


16 Ocak 2021 Cumartesi

DeadLock işlemlerinden Kaçınma


Kilitlenmeyi önleyebileceğimiz teknikler;

1- Kaynaklara aynı fiziksel sırayla erişim,

2-Erişilen kaynakların sayısının azaltılması,

3-Kilit çelişkisinin azaltılması.



1- Kaynaklara Aynı Fiziksel Sıra ile Erişim 

Aynı fiziksel düzendeki kaynaklara her işlemin eriştiğinden emin olunması gerekiyor. Her işlem kaynaklara aynı fiziksel sırada erişirse ilk işlem başarılı gerçekleşecek ikinci işlem tarafından engellenmeden işini bitirecektir. ikinci işlem işine devam edebilecektir.  İlk işlem işini bitirmeden ikinci işlem kaynağa erişime çalışırsa bu sefer birinci işlem işlemi bloke edecektir. Buda dairesel bir engellemeye yol açacaktır. 


İşlemlerden;

Transaction-1 [Access Resource 1] + [Access Resource 2]

Transaction-2 [Access Resource 2] + [Access Resource 1]

Resource 1, hobtid=72057594046578688: This is the index row within index
      PK_ PurchaseOrderDetail_PurchaseOrderId_PurchaseOrderDetailId on the
      Purchasing.PurchaseOrderDetail table.

Resource 2, hobtid=72057594046644224: This is the row within clustered index
PK_PurchaseOrderHeader_PurchaseOrderId on the Purchasing.PurchaseOrderHeader table.


Yukarıdaki mesaj kilitlenme senaryosuna örnek mesajı teşkil etmektedir. 

2- Erişilen Kaynak Sayısının Azaltılması

Bir kilitlenme en az iki kaynak içerir. Bir otorum bir kaynağı tutar ve ardından ikinci kaynağı ister. Diğer oturum ikinci kaynağı tutar ve ilk kaynağı ister. Çıkmaza dahil olan kaynaklardan birine erişirseniz kilitlenmeyi önleyebilirsiniz. Dirençli bir çözüm olarak uygulama yeniden tasarlanarak bu önlenebilir. Ancak, Uygulama tasarımı değiştirilmeden SQL Server aşağıdaki özellikleri kullanmayın düşünebilirsiniz.

* Kümelenmemiş bir dizinin kümelenmiş bir dizine dönüştürülmesi.
* SELECT ifadesi için bir kaplama index kullanılması.

* Kümelenmemiş bir dizinin kümelenmiş bir dizine dönüştürülmesi.

Kümelenmiş ve kümelenmemiş dizinin sayfaları birbirlerinden farklıdır. Kümelenmemiş dizin iki kilit alır, biri taban (küme veya yığın) diğeri kümelenememiş dizin. Kümelenmemiş dizinde yaprasak sayfaları ve dizinin veri sayfaları tabloda aynıdır. Tek kilit gerektirir, bu kilit hem kümelenmiş dizini hemde tabloyu korur. Sebebi yaprak sayfaları ve veri sayfaları aynıdır. Bu aynı sorgu ile erişilecek kaynakların sayısı azaltılır. (Ancak kümelenmemiş bir dizine karşı bu geçerlidir.) Bu işin çalışması için tamamen bunun uygun kümelenmiş index olmasına bağlıdır.

* SELECT ifadesi için bir kaplama index kullanılması.

SELECT ifadesi kaplama dizinin kendisinden her şeyi alabilir. Teme tabloya erişmesine gerek yoktur. SELECT deyiminin temel tabloya erişimini durdurarak temel  tabloyu başka bir oturum tarafından kilitlenir.

3 Ocak 2021 Pazar

DeadLock Analiz #2



Öncelikle kilitlenme bayrağı 1222 ve xml_deadlock_report olaylarının kullanıma açıldığından emin olmamız gerekiyor.

Tek bir bağlantıda aşağıdaki komut çalıştırılabilir;

BEGIN TRAN
UPDATE Purchasing.PurchaseOrderHeader
SET Freight = Freight * 0.9 -- 10% discount on shipping
WHERE PurchaseOrderID = 1255;

ikinci bağlantıda aşağıdaki komut çalıştırılabilir.

BEGIN TRANSACTION
UPDATE Purchasing.PurchaseOrderDetail
SET OrderQty = 4
WHERE ProductID = 448
AND PurchaseOrderID = 1255;

Yukarıdaki komutlar çalıştırıldığında her biri bir işlem açar ve verileri işlemeye başlar. Ancak ne kadar zamanda işlemi yapacağını ve geri alacağını bilemiyoruz.

Birinci komuta gidip aşağıdaki işlemi çalıştırılalım;

UPDATE Purchasing.PurchaseOrderDetail
SET OrderQty = 2
WHERE ProductID = 448
AND PurchaseOrderID = 1255;

İlk bağlantı büyük ihtimalle bir kaç saniye sonra bir kilitlenme oluşacaktır. 

Msg 1205, Level 13, State 51, Line 1
Transaction (Process ID 52) was deadlocked on lock resources with another process and has been
chosen as the deadlock victim. Rerun the transaction.

Önce izleme olayı aracılıyla toplanan kilitlenme grafiğini incelememiz ardından xml_deadlock_report olay için bu pencerede verilen grafiği incelememiz gerekir. 

Ancak daha detaya inerek kilitlenme olayının tam olarak nerede olduğu hangi süreçlerin buna neden olduğu hangi nesnelerin dahil edildi bilgileri XML dosyasını doğrudan genişletilmiş olay grafiğini değerlerinden bulabiliriz.


Örnek tabloda uPurchaseOrderDetail adlı bir tetikleyici bulunuyor. Tüm bu bilgiler hangi kod parçalarının kilitlenmeye yol açtığını belirlememizde yardımcı olacaktır. Ayrıca SQL Handle  gibi bilgileri almak, DMO lar ile birlikte ifadeleri almak kilitlenme ile ilgili bilgilerde bize yardımcı olacaktır.

İzleme bayrağı 1222 tarafından toplanan veriler ile XML içerisindeki bilgiler hemen hemen aynıdır.  Ana farklılıkları biçimlendirme ve konumudur. İzleme bayrağı 1204 tarafından toplanan veriler ise tamamen farklıdır.  Kullanabiliyorsanız Genişletilmiş olayları kullanmaya devam etmeniz işinizin kolaylaşması açısında daha iyidir. 1222 takip edilmesi genellikle önerilir. system_health içinde oluşan bilgilerde size yardımcı olacaktır. 

Yukarıdaki örnekde kilitlenme Purchasing.PurchaseOrderDetail  tablosundaki bir tetikleyiciden kaynaklanmaktadır. Miktar güncellendiğinde Purchasing.PurchaseOrderDetail tablosunda Purchasing.PurchaseOrderHeader tablosu güncellemeye çalışır. İlk iki sorgu çalıştığında her biri açık bir işlem üzerinde bir engelleme durumu söz konusu olur. İkinci sorgu ilk sorgunun temizlenmesini bekler böylece Purchasing.PurchaseOrderHeader tablosunu güncelleyebilir. Sorunu çözebilmek için süreçlerden birini öldürmektir.


27 Aralık 2020 Pazar

Deadlock Analiz #1

 



Oluşan sorunların nedenlerini analiz ederken sonradan oluşabilecek sorunları önleyebiliriz.

* Deadlock oturumları
* Deadlock oluşturan kaynaklar
* Sessionlar tarafından yürütülen sorgular.


Kilitlenme Bilgilerinin Toplanması 

Bu bilgileri toplamanın 4 yolu vardır.

1-1222 flag izlemesinin ayarlanması
2-1204 flag izlemesinin ayarlanması
3-İzleme olaylarının kullanılması
4-Genişletilmiş olayların kullanılması


İzleme bayrakları kilitlenme durumlarının oluşmasında belirli SQL Server davranışlarının özelleştirmesi için kullanılır. Ancak bu bilgi edinme eski bir yöntem olmuştur. SQL Server 2008 den beri kullanılan örnekte; system_health adın bir genişletilmiş olay oturumu vardır. Oturum otomatik olarak çalışır ve olaylarından birini varsayılan olarak toplar. Bu kilitlenme bilgilerine anında erişmek için en kolay yoldur.

System_health sadece anlık olayları için kullanılabiliyor. Verileri yakalamak için ring_buffer kullanıldığı için bir kilitlenme yaşandıktan hemen sonra bu parametreye bakıyorsanız bilgilerin eksik olduğunu görebileceksiniz. Daha uzun süreli bilgi toplamak gerekli olursa mümkün olduğunda çok olay toplamamız gerekiyor.  Genişletilmiş olaylar kilitlenme bilgilerini toplamak için birkaç yol sağlamaktadır. Bu en iyi yollardan biridir. 

1- Lock_deadlock: Bir kilitlenme olayı hakkkında temel bilgileri görüntülenmesini sağlar.

2-Lock_deadlock_chain: bir kilitlenmedeki her oturumda bilgi alır.

3-Xml_deadlock_report : Kilitlenme nedeniyle beraber XML şeklinde grafik sağlar.

Temel kilitlenme bilgileri için en kolay yol xml_deadlock_report görünüyor. Aynı zamanda Lock_deadlock_chain kullanmak yardımcı olacaktır.

Kilitlenme grafiğini Management Studioda açabiliriz. XMLde de arama yapabiliriz.  XML kilitlenme için neredeyse bir yürütme planı gibi çalışır.

Kilitlenme bilgisini oluşturan iki izleme bayrağı farklı veriler oluşturmak için tek tek veya birlikte kullanılabilir.

Genellikle biri kullanılır bunu sebebi ise çok fazla veri olmasındandır.  SQL Server hata günlüğünü, izleme bayraklarını, toplanan verileri, kilitlenme olaylarını bir günlük dosyasına yazar. İzleme bayrağı 1222 kilitlenme olayları ile ilgili olarak ayrıntılı bilgiler çıkarır. Bilgileri kaynağa göre sıralar ve süreçler hakkında daha fazla bilgi sağlar.

İzleme bayrağı1204 ise; kilitlenme nedenini analiz etmemize yardımcı olarak ayrıntılı kilitlenme bilgileri sağlar. Kilitlenmeye dahil olan tüm düğümleri ayrıntılı olarak çıkarır.

DBCC TRACEON izleme bayraklarını açmak ve etkileştirmek için kullanılır. Açılan izleme bayrakları DBCC TRACEOFF  deyimi kullanılana kadar devrede kalır. Eğer sunucu yeniden başlatılırsa bu izleme bayrakları silinecektir. 

DBCC TRACESTATUS deyimini kullanarak izleme bayraklarının durumunu belirleyebiliriz.


DBCC TRACEON (1222, -1);
DBCC TRACEON (1204, -1);


SQL Server Management Studio üzerinden izleme bayraklarının ayarlanması başlangıçta yapılabilir. 


19 Aralık 2020 Cumartesi

SQL Server Deadlock #1


 

Deadlock birincil nedenlerinden biri performans düşüklüğü gelir. iki veya daha fazla işlem arasında bir kilitlenme meydana geldiğinde SQL Server sadece bir işleme izin verir. Daha sonra diğer işlem(ler) için tamamlamak , sonlandırmak yada geri almak için bir hata döndürür. Kullanıcıya bu konuda yeniden denemesini sağlatmak yada işlemi sonlandırmak.

Kilitlenme, iki işlemin birbiri tarafından engellendiği özel bir engelleme senaryosudur. Her süreç kendi kaynaklarını elinde tutarak diğer işlem tarafında kilitlenen bir kaynağa erişmeye çalışır.

SQL Server işlemin geri alınması maliyetini değerlendirerek oturumu kilitleme kurbanı olarak belirler. Oturumdaki en düşük olanı seçer.  Bu alanda bir kontrol uygulanabilir. Bağlantı düşük olarak seçilerek bu işlemi yönetebiliriz.

SET DEADLOCK_PRIORITY LOW;

SET komutu yürüterek bağlantının kilitlenme önceliğini normal değere atayabiliriz.

SET DEADLOCK_PRIORITY NORMAL;


Deadlock tespiti için Error Handling Kullanmak 

SQL Server kurban olarak bir oturumu seçtiğinde hata numarası ile bir hata oluşturur. Bu hata numarasını ve hatayı bulabilmek için TRY - CATCH yapısını kullanabiliriz.

Hata işleyicisinde kilitlenme durumda hatayı uygulamaya döndürmeden önce T-SQL içerisinde birkaç kez yeniden başlatmayı deneyelim. 

DECLARE @retry AS TINYINT = 1,
      @retrymax AS TINYINT = 2,
      @retrycount AS TINYINT = 0;
WHILE @retry = 1
      AND @retrycount <= @retrymax
      BEGIN

            SET @retry = 0;
                   

            BEGIN TRY
                  UPDATE HumanResources.Employee
                  SET LoginID = '54321'
                  WHERE BusinessEntityID = 100;

            END TRY
            BEGIN CATCH

                  IF (ERROR_NUMBER() = 1205)
                        BEGIN
                              SET @retrycount = @retrycount + 1;
                              SET @retry = 1;
                        END

            END CATCH
END

Try, Catch blogu içerisinde hata numrasını bulabiliriz. Kilitlenme olup olmadığını kontrol edebilmek içinse, ERROR_NUMBER()  fonksiyonunu kullanabiliriz Kilitlenme ile karşılaşıldığında belirli bir sayıda işlemi yeniden başlatırız. Arasıra ortaya çıkan kilitlenmelerde kısa çözüm sağlayacaktır.  En iyi yaklaşım ise kilitlenmenin ana nedenini bulmaktır.

12 Aralık 2020 Cumartesi

Hashing için Tuzlama

 Düz hashing ile temel sorun belirli bir çıktının karşılık gelen girdiye eşlenmesidir. Önceden hesaplanabilir ve saklanabilir. Bu soruna kolay bir çözüm tuzlamadır. Eklenen rastgele bir dizenin hashing işleminden önce veriler eklenir böylece çıktı önceden hesaplanmış eşlemeler kullanılarak geriye döndürülemez. Sözlüğe dayalı saldırılar dahil olmak üzere hash üzerindeki tüm saldırılar istinalar dışında etkisiz hale getirilir. 


Tuz değerini daha uzun tutmak her mesaj için benzersiz bir tuz değeri kullanmak önemlidir.


Saldırgan kaba kuvvet saldırısı düzenler ve arama tablolarını kullanarak saldırı sürecini ileri almasını sağlar.  Kaba kuvvet saldırısı yapılabilen anahtar germe diye bilinen bir teknik vardır.  Bu işlem o kadar işi yavaşlatacak ki, hash'i kırmak en azından bir saldırgan bakış açısından birkaç ay onu kırmamak kötü sonuçları beraberinde getirecektir.


Parola Tabanlı Anahtar Türetme İşlevi 2 (PBKDF2) RSA  nin bir parçası olan anahtar türetme işlevidir. PKCS serisinin PKCS # sürümü 2.yayınlanmış,RFC 2898 olarak üretilen bir önceki standart olan PBKDF1 in yerini almıştır.  160 bit uzunluğa kadar türetilmiş anahtarlardır.


PBKDF2 algoritması benzer anahtar genişletme içi  standart algoritmalar bulunur. Girdiyi hash eder bir tuz değeri ile birlikte şifre veya verileri türetilmiş bir anahtar oluşturur ve bu işlemi bir çok kez tekrar eder.


Hashing , Brute-Force saldırıları bir saldırgan için zaman alıcı ve sinir bozucu hale getirir. Önerilen yineleme sayısı 1000 dir. Yineleme sayısı ne kadar yüksekse o kadar daha fazla CPU gücüne ve zamana ihtiyacı olması gerekir. Ancak bu işlemlerle verilerimizi daha güvenli hale getirebileceğiz. 


Tuzlama (Salt) ve PBKDF2 kullanarak bir SHA-1 hash oluşturulan kod aşağıda örnek amacıyla paylaşılmıştır. Rfc2898DeriveBytes sınıfı SHA-1 tabanlıdır. Bunun sonucunda elde edilen karma değer örnekteki gibi SHA256 değil, SHA-1 dir.


string data = "hello";
byte[] salt = new Byte[32];
using (var provider = new RNGCryptoServiceProvider())
{
provider.GetBytes(salt);
}
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(data, salt);
pbkdf2.IterationCount = 1000;
byte[] hash = pbkdf2.GetBytes(32);
string hashString = Convert.ToBase64String(hash);
 
 


Bu adımları nasıl kullanabileceğimiz için küçük bir alıştırma; Kullanıcı tablomuzda user_id ve password sütunlarına sahip olduğumuzu düşünelim bir sütun daha ekleyelim. Salt ve Store_hashString. Tuz değerini olduğu gibi saklayabiliriz. Bayt dizisi şeklinde, Onu bsa64 olarak kodlayabiliriz.

Kullanıcı yeniden oturum açmak istediğinde kullanıcı kimlik bilgilerini nasıl doğrulayacağının yolunu bulacağız.


string password = String.Empty; // Placeholder, şifreyi databaseden alıyoruz.
string saltString = String.Empty; // Placeholder, salt değeri databaseden alıyoruz.
string userEnteredPassword = String.Empty; // User input
var pbkdf2 = new Rfc2898DeriveBytes(userEnteredPassword, Convert.FromBase64String(saltString));
pbkdf2.IterationCount = 1000;
byte[] computedHash = pbkdf2.GetBytes(32);
bool isAuthenticCredential = password.Equals(
Convert.ToBase64String(computedHash),
StringComparison.Ordinal);


Not:

Veritabanındaki verileri şifrelemek için anahtara ihtiyacınız olacaktır. Bu anahtarı kesinlikle veritabanında saklamayın. Eğer Veritabanı SQL Injection v.b tehlikelere girerse saldırgan anahtarı ele geçirecek ve veritabanındaki şifrelerinin çözülmesi mümkün olacaktır. 


6 Aralık 2020 Pazar

Güvenli Deploma için Şifre Karıştırma

 


    Şifreleme ve Hashing arasında önemli fark hashing ile çıktının tersine çevrilememesidir. Şifrelenmiş verilerin şifresi aynı anahtar kullanılarak çözülür. Simetrik şifreleme veya asimetril şifreleme durumlarında farklı anahtar kullanılır. Hashing uygulanmış veriler sonsuz kadar karma kalır. 

Bir algoritma kullanarak 123456 için "dünya barışı" karıştırırsak ve karma veriyi depolama alanımızda saklarsak buna gerek kalmıyor. Kötü niyetli birinin 123456 dan saklanmış veri olan "dünya barışı" çıkarabilmesi için endişelenebiliriz.  Algoritma aracılıyla "dünya barışı" dan çevirdiğinizde 123456 verilecek. Hashing kullanımını burada devreye almayı amaçlıyoruz. Kullanıcı sistemimize giriş yaptığında giriş için kullandığı şifre hassas bilgi içerdiği için  girilen parolayı hashlemek, hash için daha önceden kaydettiğimiz sonuçla karşılaştırma işlemini yapmak. Karma oluşturma şifre gibi beklemedeki hassas verileri korumak için ideal bir teknik.

Not: Hashinh güvenlik gereksinimleri için tüm verileri üzerinde kullanılabilecek bir yöntem maalesef değildir. Kredi kartlarına hashing uygulayamayız, Kredi kartları hash den kurtarılamaz.


Hashing için birden fazla algoritma mevcuttur. MD5 mesaj özeti algoritması yaygın olarak kullanılan 128 bitlik (16 baytılı) karma değer üreten algoritmadır. Kriptografi dünyasında öncülük eden birkaç zayıflığı olan Güvenlik Karma Algoritması (SHA-1) güvenlik açıkları tespit edildi. Şu anda önerilen SHA-2,SHA-3 algoritmaları.


.NET Frameworde kullanılan System.Security.Crytography alanındaki sınıflarada karşılık gelen MD5,SHA1,SHA256, SHA384, SHA512 algoritma ailesi, 256,384,512 bitlik aile ise SHA-2 ailesine aittir.


"Supercalifragilisticexpialidocious" datayı Sha256 da oluşturma için küçük  bir kod.


string data = "Supercalifragilisticexpialidocious";
SHA256 hasher = SHA256.Create();
byte[] hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(data));
string hashString = BitConverter.ToString(hash).Replace("-", "").ToLower();
  

Hash kod oluşturmak son derece basittir. ComputeHash yöntemiyle yapılan bir çağrım  sonucu verecektir. BitConverter sınıfı ile bayt dizisini 16 lık dize gösterimine yardımcı olacaktır.

Hash Output:

94730f57d7e41018d963d92fbf11618dce8274ca2c1bf72274e0285a6013c17b
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
 
 


Hash kaba kuvvet kullanarak saldırabiliriz. Anında a değerini hesaplayabiliriz. Eşleme yoksa b ile devam edebiliriz. Z ye geldiğimizde aa ile başlarız ve bu şekilde devam edebiliriz. Bunun gerçekleşmesi biraz zaman ve CPU gücü alacaktır.

Bir sözcükteki sözcükler gibi karmayı önceden hesaplamak mümkündür. Karma girildiğinde sadece arama meselesine dönüşür. Hashing orjinal şifre saklama için iyi br seçim gibi görünür.  Kötü niyetli bir kişi string türünden şifreyi çevrim için araçlarla kolay biçimde elde edebilir.

Bir sonraki makalede hash ek Tuzlama işlemine yer vereceğiz.



14 Nisan 2019 Pazar

ASP.Net Web API TFA Uygulaması



Merhaba,

Google Authenticator tarafından oluşturulan TOTP kodları kullanarak ASP.NET  Web Api si ile istek başına TFA kullanımından kısaca bahsedeceğim.

ASP.NET Web API normalde bir faktöred dayalı kimlik doğrulama ile çalışılır. HTTP kimlik doğrulama üstbilgisi temel düzeninde gönderilen bir şifrenin bilgi faktörüdür. 

Birkaç önemli API için çağrılar, ASP.NET Web API, güvenliği iki faktörlü güvenliğe yükseltir ve TOTP kodunu ek olarak talep eder. 

Transfers Controller sınıfındaki HTTP POST işleyen eylem yöntemi, TFA kullanarak güvenceye almaya çalışacağımız şeydir. Eylem yöntemlerini seçmeli olarak güvenceye almamız gerekiyor.  TFA'yı uygulamak için Yetkilendirme filtresini alt sınıfa seçeriz. Bu filtre, TOTP kodunun istemci uygulaması tarafından özel bir HTTP isteği başlığında adının gönderilmesini bekler.  Tüm API çağrıları için parolanın bilgi faktörü gerekir. Dolayısıyla, ilgili kimlik doğrulama bir mesaj işleyicide mantık uygulanacak.

Aşağıda, istek başına TFA sabitini uygulamak için gereken adımlar vardır.

Transfers Controller sınıfının HTTP POST eylem yöntemi:



public class BasicAuthenticationHandler : DelegatingHandler
{

 private const string SCHEME = "Basic";
 protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
 var headers = request.Headers;
  if (headers.Authorization != null && SCHEME.Equals(headers.Authorization.Scheme))
  {
    string credentials = Encoding.UTF8.GetString(Convert.FromBase64String(                                                                                                                  headers.Authorization.Parameter));
    string[] parts = credentials.Split(':');
    string userId = parts[0].Trim();
    string password = parts[1].Trim();
     // TODO - Kullanıcı id ve şifrenin burada saklandığının doğrulanması.

if (true)
{
   var claims = new List<Claim>
{
  new Claim(ClaimTypes.Name, userId)
};


var principal = new ClaimsPrincipal(new[] {new ClaimsIdentity(claims, SCHEME) });

Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
   HttpContext.Current.User = principal;
}
}

 var response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
  response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(SCHEME));
}
  return response;
}
}





Mesaj işleyicileri listesine eklemek; 
App_Start klasörü altındaki WebApiConfig.cs,  config.MessageHandlers.Add

(new BasicAuthenticationHandler ());



  • HttpRequestMessage sınıfına bir uzantı yöntemi ekleyeceğiz,
  • Helpers klasöründe RequestHelper adlı yeni bir statik sınıf oluşturacağız.
  • Sınıfı oluşturmadan önce klasörü oluşturacağız,
  • TOTP kodu X-TOTP'de mevcutsa, yöntem onu alır.
  • Sonra statik bir yöntem GetPastCurrentFutureOtp çağırır Son 30 saniyeye karşılık gelen Totp sınıfında bloklanan üç TOTP kodunu döndürülür , şuanki  TOTP ve bir sonraki 30 saniyelik bloğa karşılık gelen ikinci TOTP bloklarına uyanlar alınır.

Örnek aşağıdaki gibi olacaktır.

Bu kod çalıştırıldığında saatin 08:35:07 AM olduğunu kabul ettiğimizde bize aşağıdaki gibi 3 TOTP kodu dönecektir.

  1. TOTP zaman aralığındaki 08:34:30 AM–08:34:59 AM (Geçmiş).
  2. TOTP zaman aralığındaki 08:35:00 AM–08:35:29 AM (Şuanki).
  3. TOTP zaman aralığındaki 08:35:30 AM–08:35:59 AM (Gelecek)  


RequestHelper Sınıfını eklemek;

public static class RequestHelper
{
 public static bool HasValidTotp(this HttpRequestMessage request, string key)
{
 if (request.Headers.Contains("X-TOTP"))
{
   string totp = request.Headers.GetValues("X-TOTP").First();
   // Geçmiş , şimdiki ve gelecekteki TOTP kontrolü
 
  if (Totp.GetPastCurrentFutureOtp(key).Any(p => p.Equals(totp)))
   return true;
}
   return false;
}
}
  


Gelen TOTP gelen 3 şifreden biri ile eşleşiyorsa kodun doğruluğu kabul edilir.  Buradaki 3 OTP den birinin olmasının nedeni ise Sunucudaki saatin, mobil telefondaki saatin, kodun çalıştığı yerdeki saatin Google Authenticator tarafından oluşturulmasıdır.


Infrastructure  klasöründe yeni bir Totp adında sınıf oluşturup, Listede sadece GetPastCurrentFutureOtp  fonksiyonu yer alsın.



public class Totp
{
public static IList<string> GetPastCurrentFutureOtp(string base32EncodedSecret)
{

DateTime epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc);
long counter = (long)Math.Floor((DateTime.UtcNow - epochStart).TotalSeconds / 30);
var otps = new List<string>();
otps.Add(GetHotp(base32EncodedSecret, counter - 1)); // Bir önceki  OTP
otps.Add(GetHotp(base32EncodedSecret, counter)); // Şuanki OTP
otps.Add(GetHotp(base32EncodedSecret, counter + 1)); // Bir sonraki OTP
return otps;
}
private static string GetHotp(string base32EncodedSecret, long counter)
{
byte[] message = BitConverter.GetBytes(counter).Reverse().ToArray(); 
byte[] secret = base32EncodedSecret.ToByteArray();
HMACSHA1 hmac = new HMACSHA1(secret, true);
byte[] hash = hmac.ComputeHash(message);
int offset = hash[hash.Length - 1] & 0xf;
int truncatedHash = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16) |((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
int hotp = truncatedHash % 1000000;
return hotp.ToString().PadLeft(6, '0'); 

}
}



Daha önceden kullanılan delegasyon işleyicisi şifrenin bilgi faktörüne dayanan doğrulanmış kimliğini oluşturur.

Kullanıcı adı alınması için IsAuthorized yöntemini override ederek, messagehandler  Thread.CurrentPrincipal üzerinden kullanalım.

Kullanıcı için örnekte hardcoded şifre girişi yapılmıştı. Bunun yerine otomatik üretiken şifre kullanılması daha uygun olur. 

HasValidTotp uzantısını kullanarak, gelen TOTP'yi doğrulayın ve geri dönün, Gelen TOTP geçerliyse geçerlidir. Aksi takdirde, false döndürün.

Burada false döndürmek, 401 yanıt statüsüne neden olur ( Yetkisiz.)
401 ile birlikte, TOTP’nin gerektirdiğini belirten bir sebep ifadesi gönderin.

HandleUnauthorizedRequest yönteminin geçersiz kılınması sağlamak.

Two Factor Attribute sınıfı Infrastructure klasörü altında yaratalım.



public class TwoFactorAttribute : AuthorizeAttribute
{

protected override bool IsAuthorized(HttpActionContext context)
{

  IIdentity identity = Thread.CurrentPrincipal.Identity;
  if (identity.IsAuthenticated && !String.IsNullOrWhiteSpace(identity.Name))
{

string key = "JBSWY3DPEHPK3PXP";
if (context.Request.HasValidTotp(key))
{
 return true;
}
}
 return false;
}

protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{

actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
ReasonPhrase = "TOTP code required"
}; } }
  



TransfersController adı ile yeni bir  Web API denetleyicisi oluşturup, İşlem sonrasında Two Factor filtresini uygularız. 

İstek sonucunda geçerli bir TOTP içeren X-TOTP başlığı içerdiğinden emin olmamız lazım, Değilse 401 izinsiz durum kodu geri döndürürüz.