- One of the trickiest, and yet most important, areas - of testing web sites is the security. - Testing these schemes is one of the core goals of - the SimpleTest web tester. -
- -
-
-Basic HTTP authentication
-
-
- If you fetch a page protected by basic authentication then - rather than receiving content, you will instead get a 401 - header. - We can illustrate this with this test... -
-class AuthenticationTest extends WebTestCase {
- function test401Header() {
- $this->get('http://www.lastcraft.com/protected/');
- $this->showHeaders();
- }
-}
-
- This allows us to see the challenge header...
- File test
--HTTP/1.1 401 Authorization Required -Date: Sat, 18 Sep 2004 19:25:18 GMT -Server: Apache/1.3.29 (Unix) PHP/4.3.4 -WWW-Authenticate: Basic realm="SimpleTest basic authentication" -Connection: close -Content-Type: text/html; charset=iso-8859-1 --
-class AuthenticationTest extends WebTestCase {
- function test401Header() {
- $this->get('http://www.lastcraft.com/protected/');
- $this->assertAuthentication('Basic');
- $this->assertResponse(401);
- $this->assertRealm('SimpleTest basic authentication');
- }
-}
-
- Any one of these tests would normally do on it's own depending
- on the amount of detail you want to see.
-
- - Most of the time we are not interested in testing the - authentication itself, but want to get past it to test - the pages underneath. - As soon as the challenge has been issued we can reply with - an authentication response... -
-class AuthenticationTest extends WebTestCase {
- function testAuthentication() {
- $this->get('http://www.lastcraft.com/protected/');
- $this->authenticate('Me', 'Secret');
- $this->assertTitle(...);
- }
-}
-
- The username and password will now be sent with every
- subsequent request to that directory and subdirectories.
- You will have to authenticate again if you step outside
- the authenticated directory, but SimpleTest is smart enough
- to merge subdirectories into a common realm.
-
- - You can shortcut this step further by encoding the log in - details straight into the URL... -
-class AuthenticationTest extends WebTestCase {
- function testCanReadAuthenticatedPages() {
- $this->get('http://Me:Secret@www.lastcraft.com/protected/');
- $this->assertTitle(...);
- }
-}
-
- If your username or password has special characters, then you
- will have to URL encode them or the request will not be parsed
- correctly.
- Also this header will not be sent on subsequent requests if
- you request a page with a fully qualified URL.
- If you navigate with relative URLs though, the authentication
- information will be preserved.
-
- - Only basic authentication is currently supported and this is - only really secure in tandem with HTTPS connections. - This is usually enough to protect test server from prying eyes, - however. - Digest authentication and NTLM authentication may be added - in the future. -
- -
-
-Cookies
-
-
- Basic authentication doesn't give enough control over the - user interface for web developers. - More likely this functionality will be coded directly into - the web architecture using cookies and complicated timeouts. -
-- Starting with a simple log-in form... -
-<form> - Username: - <input type="text" name="u" value="" /><br /> - Password: - <input type="password" name="p" value="" /><br /> - <input type="submit" value="Log in" /> -</form> -- Which looks like... - -
-
- -- Let's suppose that in fetching this page a cookie has been - set with a session ID. - We are not going to fill the form in yet, just test that - we are tracking the user. - Here is the test... -
-class LogInTest extends WebTestCase {
- function testSessionCookieSetBeforeForm() {
- $this->get('http://www.my-site.com/login.php');
- $this->assertCookie('SID');
- }
-}
-
- All we are doing is confirming that the cookie is set.
- As the value is likely to be rather cryptic it's not
- really worth testing this.
-
- - The rest of the test would be the same as any other form, - but we might want to confirm that we still have the same - cookie after log-in as before we entered. - We wouldn't want to lose track of this after all. - Here is a possible test for this... -
-class LogInTest extends WebTestCase {
- ...
- function testSessionCookieSameAfterLogIn() {
- $this->get('http://www.my-site.com/login.php');
- $session = $this->getCookie('SID');
- $this->setField('u', 'Me');
- $this->setField('p', 'Secret');
- $this->clickSubmit('Log in');
- $this->assertWantedPattern('/Welcome Me/');
- $this->assertCookie('SID', $session);
- }
-}
-
- This confirms that the session identifier is maintained
- afer log-in.
-
- - We could even attempt to spoof our own system by setting - arbitrary cookies to gain access... -
-class LogInTest extends WebTestCase {
- ...
- function testSessionCookieSameAfterLogIn() {
- $this->get('http://www.my-site.com/login.php');
- $this->setCookie('SID', 'Some other session');
- $this->get('http://www.my-site.com/restricted.php');
- $this->assertWantedPattern('/Access denied/');
- }
-}
-
- Is your site protected from this attack?
-
-
-
- - If you are testing an authentication system a critical piece - of behaviour is what happens when a user logs back in. - We would like to simulate closing and reopening a browser... -
-class LogInTest extends WebTestCase {
- ...
- function testLoseAuthenticationAfterBrowserClose() {
- $this->get('http://www.my-site.com/login.php');
- $this->setField('u', 'Me');
- $this->setField('p', 'Secret');
- $this->clickSubmit('Log in');
- $this->assertWantedPattern('/Welcome Me/');
-
- $this->restart();
- $this->get('http://www.my-site.com/restricted.php');
- $this->assertWantedPattern('/Access denied/');
- }
-}
-
- The WebTestCase::restart() method will
- preserve cookies that have unexpired timeouts, but throw away
- those that are temporary or expired.
- You can optionally specify the time and date that the restart
- happened.
-
- - Expiring cookies can be a problem. - After all, if you have a cookie that expires after an hour, - you don't want to stall the test for an hour while the - cookie passes it's timeout. -
-- To push the cookies over the hour limit you can age them - before you restart the session... -
-class LogInTest extends WebTestCase {
- ...
- function testLoseAuthenticationAfterOneHour() {
- $this->get('http://www.my-site.com/login.php');
- $this->setField('u', 'Me');
- $this->setField('p', 'Secret');
- $this->clickSubmit('Log in');
- $this->assertWantedPattern('/Welcome Me/');
-
- $this->ageCookies(3600);
- $this->restart();
- $this->get('http://www.my-site.com/restricted.php');
- $this->assertWantedPattern('/Access denied/');
- }
-}
-
- After the restart it will appear that cookies are an
- hour older and any that pass their expiry will have
- disappeared.
-
-
-