16 Ocak 2012 Pazartesi

OpenSSL ile Güvenli Tünel

Selamlar,

4. sınıf güz yarı yılı derslerimizden olan Bilgisayar Ağları dersi için senenin başında hepimiz birer ödev konusu seçtik. Ve dönem sonuna kadar istediğimiz zaman sunumunu yapabilecektik. Ben ödev başlıkları içinden güvenli tüneli seçtim.

Bu konuda araştırma yapmaya başladım. Birçok kullanılan güvenli tünel uygulamaları vardı. Bunlardan bazıları uygulama olarak değişiklikler gösteriyordu. Örneğin; SSH örnek olarak verilebilir. SSH ile iş yapmak istediğiniz bir bilgisayara uzaktan bağlantı sağlayabiliyor ve bu safhada yaptığınız tüm veri aktarımını şifreli olarak gerçekleştiriyorsunuz. Bu da günümüzde SSH uygulamasında kullanılan şifreleme algoritmalarının (DES, AES, RSA, DSA gibi) kırılamayacağı inancında olduğumuz için güvenli olarak kabul ediyoruz.

Bende güvenli tünel olarak arada şifreli veri gönderimi yapan bir uygulama yazmaya karar verdim. Aynı zamanda Python dilini kullanacağım için onun ssl kütüphanesini kullanabilirdim[1]. Bu dökümantasyon sayfasını incelemeye başladım. Kullanabileceğim fonksiyonlar olduğunu gördüm. Yapmam gereken bir client bir de server tarafı yazmaktı. Bu tarafları yazarken en başta haberleşmeleri için karşılıklı portları açıp soket oluşturdum. Daha sonra ssl kütüphanesinin bana sağladığı avantajlardan biri olan "ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None) "
fonksiyonu ile oluşturduğum socketleri birer ssl socket haline getirip socketler arası bağlantı yaptım. Bu kod kısmı server tarafında dinleme şeklinde olamlıydı. Yani server tarafında soket bind işlemi yapılacak ve herhangi bir adresten gelecek bağlantı dinlenecekti. Aşağıda yazdığım kod parçalarına yer vereceğim ve hangi saturda ne oluyor yorum satırı olarak ekleyeceğim.

Kod kısmının anlatımına geçmeden kısaca wrap_socket() fonksiyonun aldığı parametreler ile ilgili bilgi vermek istiyorum.
sock, oluşturduğumuz socket nesnesi,
keyfile, certfile ise daha ileride ayrıntılı bahsedeceğim alınması gereken sertifikayı ve sonrasında kullanabildiğimiz key ve sertifika dosyalarını kastediyor.
server_side parametresi ise boolean olarak yazılan kodun server ya client davranışları gösterip göstermediğini belirtir. Yazdığım server tarafında bu parametreyi True olarak işaretledim.
cert_reqs ise sertifikanın gerekliliğinden bahsedilen kısım, kullanabileceğiniz seçenekler CERT_NONE(sertifika gerekli değil), CERT_OPTIONAL(seçimlik), CERT_REQUIRED(belirtilmesi gerekli) olarak belirlenmiş. Buradan sonraki parametrelere ben None değeri atadım. Kullanmadım.

Güvenli Tünel Uygulamamın client tarafı kodları:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket, ssl, pprint

host = '127.0.0.1' // bu kısma kendi ip adresinizi yazacaksınız, ben tek bilgisayarda denediğim için '127.0.0.1'
port = 10023 //port olarak 10023 sectim, iki taraftada aynı port kullanılmalı
addr = (host, port)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) // soket oluşturuldu

# bu kısımda server tarafından sertifika doğrulama karşılaştırma için sertifika gerekir
ssl_sock = ssl.wrap_socket(s,   //  soket
        ca_certs="/home/ssezgin/sertifikalar/certs/myca.crt",  // sertifika otoritesi
        cert_reqs = ssl.CERT_REQUIRED, // sertifika gerekli olarak belirlenmiş
        ssl_version = ssl.PROTOCOL_TLSv1 ) // kullanılan ssl versiyonu belirtilmiş.
# [2] adresinde sertifika alma işlemlerini sırasıyla ayrıntılı bir şekilde anlattım
ssl_sock.connect(addr) // yeni oluşturulan ssl soket ile bağlantı yapıldı

print repr(ssl_sock.getpeername())  // ssl objesinin fonk. ve soketin özelliklerini gösterir, (ip, port gibi)
print ssl_sock.cipher()  // hangi şifreleme formatının kullanıldığını söyler
print("DER-encoded formda:")
print pprint.pformat(ssl_sock.getpeercert(True)) // DER-encoded formda sertifikanın içeriğini gösterir
print("Duz Metin olarak:")
print pprint.pformat(ssl_sock.getpeercert())     // sertifikanın içeriğini gösterir

ssl_sock.write("deneme")  // Burada write() fonk ile şifreli gönderim yapılır.

data = ssl_sock.read() // serverdan geri dönen veriler okunur

ssl_sock.close() // artık ssl özelliği olan soket kapatılır.

Server tarafı:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket,ssl

bindsocket = socket.socket()
bindsocket.bind(('',10023))
bindsocket.listen(5000)

while True:
    newsocket, fromaddr = bindsocket.accept() // client tarafından gelen istek kabul edilir bağlantı sağlanır
    print "I got a connection from ", fromaddr

# client tarafı için gerçekleştirdiğimiz ssl soket oluşturma işlemi burada da tekrarlanır, bu aşamada sertifikanın düzgün oluşturulması gerekir, eğer hatalıysa, bağlantı reddi, karşı tarafı tanımama gibi hatalar alınarak bağlantı başlamaz server ve client arasında bu kısım gerçekten sorun oluşturabilecek tek yer
    baglanti = ssl.wrap_socket(newsocket,
            certfile = "/home/ssezgin/sertifikalar/certs/server.crt",
            keyfile = "/home/ssezgin/sertifikalar/private/server-key-cert.pem",
            server_side=True,
            ssl_version = ssl.PROTOCOL_TLSv1)

    data = baglanti.read()
    print data

    baglanti.shutdown(socket.SHUT_RDWR)
    baglanti.close()

ssl versiyonu seçilirken dikkatli olmak gerekir. ssl_version, kullanılan SSL protokolünün versiyonunu belirtir. Tipik olarak server belli bir protokol versiyonunu seçer ve client' ın server' ın seçimine uyum sağlamasını bekler. Yani client/server ssl_version eşleşmelerinde sınırlamalar vardır. Başarılı bağlantı openssl in versiyonuna bağlı olarak da değişiklik gösterebilir. Örneğin; openssl in bazı eski versiyonlarında (0.9.7l)
bir SSLv2 client bir SSLv23 server ile bağlantı kuramaz. Bir başka örnek; openSSL 1.0.0 başlangıcında sen SSLv2 bağlantısını açıkça etkinleştirmedikçe SSLv23 client SSLv2 bağlantısına teşebbüs etmeyecektir. Bu “ALL” “SSLv2” şeklinde belirtilerek sağlanabilir.

Güvenli Tünel için yazdığım kod parçaları bunlar. Ama çalışabilmesi için daha öncede belirttiğim gibi sertifika oluşturma işlemlerinin tamamlanmış, doğrulanmış hatasız çalışıyor olması gerekli. Bu yüzden [2] adresinde ayrıntılı olarak sertifika işlemlerinden bahsettim.


[1]- http://docs.python.org/library/ssl.html
[2]- http://simgesezgin.blogspot.com/2012/01/kendi-sertifika-otoritemizi-nasl.html

Hiç yorum yok:

Yorum Gönder