· 5 years ago · Feb 19, 2020, 05:08 AM
1First file (2.1.2.txt) is for 2.1.3
2
3Second file (database.py) is for 2.1.4 (Don't forget to change the netid / password to your own)
4
5Third file (defenses.py) is for 2.1.5 & 2.1.6
6
7
8CREATE TABLE users (id int unsigned NOT NULL AUTO_INCREMENT, username varchar(32) NOT NULL, salt varchar(64) NOT NULL, passwordhash varchar(64) NOT NULL, PRIMARY KEY (id), UNIQUE (username), INDEX (username));
9CREATE TABLE history (id int unsigned NOT NULL AUTO_INCREMENT, user_id int unsigned NOT NULL, query varchar(2048) NOT NULL, PRIMARY KEY (id), UNIQUE (id), INDEX (user_id));
10
11-----------------------------------------------------------------------------------------------------------------
12
13import pymysql as mdb
14from bottle import FormsDict
15from hashlib import sha256
16import os
17
18# connection to database project2
19def connect():
20 """makes a connection to MySQL database.
21 @return a mysqldb connection
22 """
23
24 #TODO: fill out MySQL connection parameters. Use the netid and password corresponding to the repo you are committing your solution to.
25
26 return mdb.connect(host="localhost",
27 user="whchan2",
28 passwd="4fd59462e2ff36fb94c58b0c873e739603c10201a1b659dd79638f249cbe67b2",
29 db="project2");
30
31def createUser(username, password):
32 """ creates a row in table named users
33 @param username: username of user
34 @param password: password of user
35 """
36
37 salt = os.urandom(32)
38 salted = salt + str.encode(password)
39
40 m = sha256()
41 m.update(salted)
42 passwordhash = hex(int.from_bytes(m.digest(), byteorder="big"))[2:]
43 salt = hex(int.from_bytes(salt, byteorder="big"))[2:]
44
45 db_rw = connect()
46 cur = db_rw.cursor()
47 #TODO use cur.execute() to insert a new row into the users table containing the username, salt, and passwordhash
48 sql = "INSERT INTO `users` (`username`, `salt`, `passwordhash`) VALUES (%s, %s, %s)"
49 cur.execute(sql, (str(username), str(salt), str(passwordhash)))
50
51 db_rw.commit()
52
53def validateUser(username, password):
54 """ validates if username,password pair provided by user is correct or not
55 @param username: username of user
56 @param password: password of user
57 @return True if validation was successful, False otherwise.
58 """
59
60 db_rw = connect()
61 cur = db_rw.cursor()
62 #TODO use cur.execute() to select the appropriate user record (if it exists)
63 sql = "SELECT salt, passwordhash FROM `users` WHERE `username` = %s"
64 cur.execute(sql, (str(username), ))
65
66 if cur.rowcount <1:
67 return False
68
69 user_record = cur.fetchone()
70 salt = bytes.fromhex(user_record[0])
71 passwordhash_authoritative = user_record[1]
72 salted = salt + str.encode(password)
73
74 m = sha256()
75 m.update(salted)
76 passwordhash = hex(int.from_bytes(m.digest(), byteorder="big"))[2:]
77
78 if passwordhash_authoritative == passwordhash:
79 return True
80 else:
81 return False
82
83def fetchUser(username):
84 """ checks if there exists given username in table users or not
85 if user exists return (id, username) pair
86 if user does not exist return None
87 @param username: the username of a user
88 @return The row which has username is equal to provided input
89 """
90
91 db_rw = connect()
92 cur = db_rw.cursor(mdb.cursors.DictCursor)
93 #TODO use cur.execute() to fetch the row with this username from the users table, if it exists
94 sql = "SELECT * FROM `users` WHERE `username` = %s"
95 cur.execute(sql, (str(username), ))
96 if cur.rowcount < 1:
97 return None
98 return FormsDict(cur.fetchone())
99
100def addHistory(user_id, query):
101 """ adds a query from user with id=user_id into table named history
102 @param user_id: integer id of user
103 @param query: the query user has given as input
104 """
105
106 db_rw = connect()
107 cur = db_rw.cursor()
108 #TODO use cur.execute() to add a row to the history table containing the correct user_id and query
109 sql = "INSERT INTO `history` (`user_id`, `query`) VALUES (%s, %s)"
110 cur.execute(sql, (user_id, str(query)))
111
112 db_rw.commit()
113
114def getHistory(user_id):
115 """ grabs last 15 queries made by user with id=user_id from
116 table named history in descending order of when the searches were made
117 @param user_id: integer id of user
118 @return a first column of a row which MUST be query
119 """
120
121 db_rw = connect()
122 cur = db_rw.cursor()
123 #TODO use cur.execute() to fetch the most recent 15 queries from this user (including duplicates). (Make sure the query text is at index 0 in the returned rows)
124 sql = "SELECT query, id FROM `history` WHERE `user_id` = %s ORDER BY id DESC LIMIT 15"
125 cur.execute(sql, (user_id, ))
126 rows = cur.fetchall();
127 return [row[0] for row in rows]
128
129-----------------------------------------------------------------------------------------------------------------
130
131import re, os, binascii
132from bottle import FormsDict, HTTPError
133from hashlib import md5
134
135############################################################
136# XSS Defenses
137
138class XSSNone(object):
139 """ this class just returns user_input """
140
141 name = "No defense"
142 @staticmethod
143 def init(response):
144 response.set_header("X-XSS-Protection", "0");
145 @staticmethod
146 def filter(user_input):
147 return user_input
148
149class XSSEncodeAngles(object):
150 """ this class encodes < and > into < and > """
151
152 name = "Encode < and >"
153 @staticmethod
154 def init(response):
155 response.set_header("X-XSS-Protection", "0");
156 @staticmethod
157 def filter(user_input):
158 #TODO: complete this filter definition
159 user_input = str(user_input).replace("<", "<");
160 user_input = str(user_input).replace(">", ">");
161 return user_input
162
163############################################################
164# CSRF Defenses
165
166class CSRFNone(object):
167 """ this class provides no defense against CSRF """
168
169 name = "No defense"
170 @staticmethod
171 def init(request, response):
172 return None
173 @staticmethod
174 def formHTML(token):
175 return ""
176 @staticmethod
177 def validate(request, token):
178 pass
179
180class CSRFToken(object):
181 """ token validation class against CSRF """
182
183 name = "Token validation"
184 @staticmethod
185 def init(request, response):
186 token = request.get_cookie("csrf_token")
187
188 #TODO: implement Token validation
189
190 if token is None :
191 token = binascii.b2a_hex(os.urandom(16)).decode()
192
193 response.set_cookie("csrf_token", token)
194
195 return token
196 @staticmethod
197 def formHTML(token):
198 return "<input type='hidden' name='csrf_token' value='" + token + "'>"
199 @staticmethod
200 def validate(request, token):
201 if request.forms.get('csrf_token') != token:
202 raise HTTPError(403, "CSRF Attack Detected (bad or missing token)")
203
204############################################################
205
206xssDefenses = [XSSNone,XSSEncodeAngles]
207csrfDefenses = [CSRFNone,CSRFToken]
208
209xssDefense = xssDefenses[0]
210csrfDefense = csrfDefenses[0]
211
212def setCookies(response):
213 response.set_cookie("xssdefense", str(xssDefenses.index(xssDefense)))
214 response.set_cookie("csrfdefense", str(csrfDefenses.index(csrfDefense)))
215
216def setup(request, response):
217 def getDefense(request, name):
218 if name in request.forms:
219 return int(request.forms.get(name))
220 elif name in request.query:
221 return int(request.query.get(name))
222 else:
223 return int(request.get_cookie(name,0))
224 global xssDefense, csrfDefense
225 xss = getDefense(request, "xssdefense")
226 if xss not in range(len(xssDefenses)):
227 raise HTTPError(output="Invalid XSS Defense (%d)" % xss)
228 csrf = getDefense(request, "csrfdefense")
229 if csrf not in range(len(csrfDefenses)):
230 raise HTTPError(output="Invalid CSRF Defense (%d)" % csrf)
231 xssDefense = xssDefenses[xss]
232 csrfDefense = csrfDefenses[csrf]
233 setCookies(response)
234
235def selectors():
236 def getSelector(defenseList, selectedDefense=None):
237 return "".join("<option value=%d%s>%d - %s</option>" % \
238 (i,(defenseList[i].name==selectedDefense.name and " selected" or ""), i, defenseList[i].name) \
239 for i in range(len(defenseList)))
240 return FormsDict(xssoptions=getSelector(xssDefenses,xssDefense),
241 csrfoptions=getSelector(csrfDefenses,csrfDefense)