Merhabalar. Bu yazımda, çoğumuzun web projelerinde ihtiyaç duyabileceği, önemli bir güvenlik ayrıntısını irdeliyeceğiz. Bir çok üyelik gerektiren websitelerinde gördüğümüz, güvenlik resimlerinin nasil oluşturulacağını inceleyeceğiz.
Öncelikle dikkat etmemiz gereken noktalara bakalim. Amacımız herhangi bir program tarafindan okunamayacak, image processing ya da benzeri algoritmalarla yorumlanamayacak fakat buna karşılık, gerçek bir kullanıcı, bir insan tarafindan çok kolay anlaşılabilecek resimler oluşturmak. Bunun için yapabileceklerimiz:
· Yeterli derecede background ve text kirliliği, dağınıklığı sağlamak
· Mümkün olduğunca birbirinden farklı, birbirine benzemeyen resimler kullanmak
· Olabildiğince çok resim kullanmak
· Resimlerin dosya büyüklüklerini (file size) mümkün olduğunca birbirine yakın hatta aynı boyutta tutmak.
Son iki madde, gerçekten çok dikkat edilmesi gereken bir özellik. Bir çok sitede,bu tarz resimler 20-30 adetle sınırlandırılmış ve de hepsinin dosya boyutları faklı olan resimler kullanılmakta. Bunların çoğunluğu image processing gibi işlemlere okunması zor olan resimler olsa da, designerlarin gözden kacırdıkları, cok daha büyük bir güvenlik açığı yaratmakta. Dosyaların büyüklükleri ve içerisindeki yazılar bir kez tespit edildikten sonra, bir program aracılığı ile flood işlemleri rahatlıkla gerçekleştirilebilir.
Peki, yapabileceğimiz ne var? Bu konuda en iyi çözüm; resmi run-time da random olarak oluşturmak ve bu şekilde içeriğindeki yazıyı kontrol etmek. Yani, örneğin, sayfa her refresh olduğunda, yeni bir kod, bu kodun resimsel, kirletilmiş, anlaşılması güçleştirilmiş hali ve de her seferinde aynı dosya adında, yaklaşık olarak aynı dosya boyutunda yeni bir resim üretmek.
Aşağıda kodunu gördüğümüz Img classı textten image oluşturmak için bütün işlemleri gerçekleştirmekte.
public class Img
{
#region properties
public string Text
get { return this.text; }
}
public Bitmap Image
get { return this.image; }
public int Width
get { return this.width; }
public int Height
get { return this.height; }
private string text;
private int width;
private int height;
private string familyName;
private Bitmap image;
#endregion
private Random random = new Random();
//uretilen kodu, yukseklik ve de genisligi kullanarak yeni bir image uretelim
public Img(string s, int width, int height)
text = s;
this.width = width;
this.height = height;
ImageYarat();
//Urettigimiz kodumuzu stringten image ceviriyoruz.
private void ImageYarat()
this.familyName = System.Drawing.FontFamily.GenericSerif.Name;
// 32bit bmp yaratalim
Bitmap bitmap = new Bitmap(this.width, this.height, PixelFormat.Format32bppArgb);
// cizim icin bir graphics nesnesi yaratalim.
Graphics g = Graphics.FromImage(bitmap);
g.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle rec = new Rectangle(0, 0, this.width, this.height);
// Resimde arka alani dolduralim
HatchBrush hb = new HatchBrush(HatchStyle.SmallConfetti, Color.LightGray, Color.White);
g.FillRectangle (hb, rec);
Font font = new Font(this.familyName, 44, FontStyle.Bold);
// textin formatini belirleyelim
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
// bir path belirleyip, texte random olarak aci verelim
GraphicsPath path = new GraphicsPath();
path.AddString(this.text, font.FontFamily, (int) font.Style, font.Size, rec, format);
float v = 4;
PointF[] p =
new PointF(this.random.Next(rec.Width) / v, this.random.Next(rec.Height) / v),
new PointF(rec.Width - this.random.Next(rec.Width) / v, this.random.Next(rec.Height) / v),
new PointF(this.random.Next(rec.Width) / v, rec.Height - this.random.Next(rec.Height) / v),
new PointF(rec.Width - this.random.Next(rec.Width) / v, rec.Height - this.random.Next(rec.Height) / v)
};
Matrix matrix = new Matrix();
matrix.Translate(0F, 0F);
path.Warp(p, rec, matrix, WarpMode.Perspective, 0);
// texti cizelim
hb = new HatchBrush(HatchStyle.LargeConfetti, Color.LightGray, Color.DarkGray);
g.FillPath(hb, path);
// biraz da gurultu/kirlilik ekleyelim
for (int i = 0; i < (int) (rec.Width * rec.Height / 30); i++)
int x = this.random.Next(rec.Width);
int y = this.random.Next(rec.Height);
int w = this.random.Next(rec.Width / 50);
int h = this.random.Next(rec.Width / 40);
g.FillEllipse(hb, x, y, w, h);
//image hazir...
this.image = bitmap;
Kodda da gördüğümüz gibi öncelikle graphics object kullanarak bir resim oluşturduk, arka alanını doldurduk, textin fontunu, formatini belirledik, texte bir path belirleyip bir perspektif ve açı kazandırdık ve son olarak, resmimize gürültü ekledik. ıstenirse, bu class çok daha geliştirilebilinir. Mesela : textin, back groundun ya da gürültünün rengi random olarak değiştirilebilinir, font-family random atanabilir....
İşte bu kadar, geriye kalan iş; bu classı çağıracak uygun web formları oluşturmak. Bunun için de iki ayrı web forma ihtiyacımız var. Bir tanesi resimi yaratacak olan img clasını çağıracak ve bir image gibi davranacak olan web form, diğeri de default.aspx olan, kodu random olarak üreten, girilen kod ile doğruluğunu test eden ve de içerisine image web formunu <img> tagı ile çağıran formumuz.
JpegImage.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
// bitmap imagei session degerini kullanarak uret.
Img ci = new Img(this.Session["ImageKod"].ToString(), 200, 50);
//Response Headerini Jpeg imageye cevir
this.Response.Clear();
this.Response.ContentType = "image/jpeg";
//resmi, response streame jpeg formatinda yazalim
ci.Image.Save(this.Response.OutputStream, ImageFormat.Jpeg);
//ci.Dispose();
Gördüğümüz gibi, JpegImage.aspx.cs img classını çağırarak 200*50 bir resim oluşturmakta.
Default.aspx.cs
if (!this.IsPostBack)
// Random bir kod uretip o kodu sessionda tutalim.
this.Session["ImageKod"] = RandomKodUret();
else // postback olduysa kod kontrolu
if (this.txtKod.Text == this.Session["ImageKod"].ToString())
//dogru
Session.Add("Guvenlik",true);
this.lblMessage.Text = "Dogru..!";
else
// yanlis
this.lblMessage.Text = "Hata..!";
// kodu degistir
this.txtKod.Text = "";
this.Session["ImageKod"] = RandomKodUret ();
// 6 rakamli random bir sayi uretir
private string RandomKodUret()
string s = "";
for (int i = 0; i < 6; i++)
s = String.Concat(s, this.random.Next(10).ToString());
return s;
Default.aspx.cs’de gördüğümüz gibi, page refresh olduğunda random bir sayı üretir. Ben bu sayının 6 rakam olmasını uygun görüyorum. 000000’dan 999999’a kadar 1milyon farklı resim elde edebiliriz, bu da fazlasıyla memnuniyet verici bir sayı. Session objesine attığımız textimizi, postback sırasında kontrol ederek, girilen değerle doğruluğunu karşılaştırıyoruz.
Son olarak, default.aspx’e de bakalim.
JpegImage.aspx’i <img> tag i ile cagirarak, projemizi tamamliyoruz.
Kodu indir
Hepimize iyi calismalar.
Kıvanç ÖZÜÖLMEZ