This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Himself12794's profile picture

Strengthening Password Server Security

Started by Himself12794, 18 February 2014 - 08:25 PM
Himself12794 #1
Posted 18 February 2014 - 09:25 PM
I'm making a computercraft network, inspired by Nitrogen Fingers, and Have just finished out ironing some bugs in my password authentication system, and would like to know if there are things I could do make things more secure, mostly by making authentication based on things a console user cannot change. I know a user could go through and change config and functions, and I want to make so that there is nothing they can do cause information to be sent to a unsecure source, or wrongly extract information.

I have several different computers, there's router files, a master server computer, sub-servers, and the client computer. What I'm most interested in is the password sub server and the client.

Here's the relevant client code:
Spoiler

rednet.open('top')
--This is a console

os.loadAPI('functions')
os.loadAPI('errors')

local function header()
	
	term.clear()
	term.setCursorPos(1,1)
	
	print('HimCo Industries\' Experimental OS')
	print()
	
end	

local function registerComputer()

	local msg=functions.ser({id=os.getComputerID(),action='registerComputer'})
	rednet.broadcast(msg)
	print('looking for valid router')
	local id=rednet.receive(5)
	if not id then
		print('Could not find valid router.')
		return false
	end
	local id,msg=functions.receiveMessage(5)
	if not id then
		print('No valid router found')
		return false
	end
	print(msg)
	textutils.tabulate(msg)
	local values=functions.unser(msg)
	
	if values['action']=='computerAdded' then
	
		print('saving router id #',values['id'],' as parent router')
		functions.saveToFile('parent_id',values['id'],'config')
		return true
		
	end

end

local function checkSession()
	
	if functions.loadFromFile('session')=='Guest' then
		return true
	end
	
	local msg=functions.ser({action='password_server',id=os.getComputerID(),value='session',username=functions.loadFromFile('session','config')})
	functions.sendMessage(parent_id,msg)
	
	local id,msg=functions.receiveMessage(3)
	
	if errors.noService(id,'error') then
		return 'error'
	end
	
	local values=functions.unser(msg)
	
	if values['user_id']==os.getComputerID() then
		functions.saveToFile('session',values['username'])
		return true
	else
		return values['value']
	end

end

local function login()
	header()
	
	write('Please give your username: ')
	local username=read()
	print()
	
	write('Please give your password: ')
	local password=read('*')
	
	local msg=functions.ser({action='password_server',id=os.getComputerID(),value='login',password=password, username=username})
	if functions.sendMessage(parent_id,msg) then
	
		local id,msg=functions.receiveMessage(5)
		
		if errors.noService(id) then
	
			print('Could not connect to server. Do you want to enter offline mode?')
			if functions.dichotomy('Go Offline','Quit') then
				functions.saveToFile('session','Guest')
			end
			
		end
			
		
		local values=functions.unser(msg)
		if values['session']~=os.getComputerID() then
		
			print('That profile is already open on computer #',values['session'],'. Please logout there, and try again.')
			sleep(2)
			os.reboot()
			
		elseif values['value'] and values['session']==os.getComputerID() then
		
			print('User ',username,' has been logged in.')
			functions.saveToFile('session',username)
			sleep(2)
			return true
			--os.reboot()
			
		else
			sleep(2)
			print('Username and password combination do not match')
			sleep(2)
			os.reboot()
			
		end	
	else
		print('Could not connect to server. Do you want to enter offline mode?')
		if functions.dichotomy('Go Offline','Quit') then
			functions.saveToFile('session','Guest')
		else
			os.reboot()
		end
	end
end

local function registerAccount()

	local password
	local username
	
	while true do
		
		header()
		write('Give a username: ')
		username=read()
		
		write('Give a password: ')
		password=read('*')
	
		write('Please confirm password: ')
		local tmp=read('*')
	
		if tmp==password then break end
		print('Passwords do not match, please try again')
		sleep(1.5)
	
	end

	local msg=functions.ser({action='password_server',id=os.getComputerID(),value='create',password=password,username=username})
	functions.sendMessage(parent_id,msg)

	local id,msg=functions.receiveMessage()

	local values=functions.unser(msg)
	
	if values['action']=='return' and values['value'] then
	
		print('Account created.')
		sleep(2)
		os.reboot()
	
	else
	
		print('Account already exists.')
		sleep(2)
		os.reboot()
		
	end
	
end
	

local function validate(parent_id)

	local choices={
		'Login',
		'Create Account',
		'Shutdown'
	}

	local choice=functions.multipleChoice(choices,1,2)
	if not choice then
		os.reboot()
	end
	
	if choice==1 then

		login()
	
	elseif choice==2 then
		
		registerAccount()
		
	elseif choice==3 then
	
		os.shutdown()
		
	end
end

functions.createFile('config')

if not functions.loadFromFile('parent_id','config') then

	registerComputer()
	
end

parent_id=functions.loadFromFile('parent_id')

local session=checkSession()

if not session then

	header()
	validate(parent_id)

elseif session=='error' then
	
	print('Could not connect to server. Do you want to enter offline mode?')
	if functions.dichotomy('Go Offline','Quit') then
		functions.saveToFile('session','Guest')
	else
		os.reboot()
	end
	
end
shell.setDir('files')
shell.run('menu')

Here is the password server code:
Spoiler


os.loadAPI('functions')
rednet.open('top')
shell.run('clear')
local function header()
	functions.lineClear()
	functions.printCentered('This is the password server')
	functions.lineClear()
	print()
	functions.lineClear()
	print('Computer:  #',os.getComputerID())
	functions.lineClear()
	print('Parent Computer:  #',parent_id)
	functions.lineClear()
	print()
	functions.lineClear()
	print('===================================================')
	functions.lineClear()
	print()
end

local function getParentId()
	parent_id=functions.loadFromFile('parent_id','config')
	if not parent_id then
		while true do
			local parent_id=functions.numbersOnly('Please give the id of the parent router: ',3)
			local msg=functions.ser({action='registerSubServer',id=os.getComputerID(),value='password_server'})
			if functions.sendMessage(parent_id,msg) then
				functions.saveToFile('parent_id',parent_id,'config')
				break
			else
				print('The requested router could not be found. Please check its availability, or try another id.')
			end
			sleep(0.01)
		end
	end
	return parent_id
end

local function manager(msg)
	local values=functions.unser(msg)
	functions.lineClear()
	print('Received message from Computer #',values['id'])
	functions.lineClear()
	print('Value is ',values['value'])
	local verify=false
	-------------------------------------
	if values['value']=='create' then
	--[----------------------------------
		if not functions.loadFromFile(values['username'],'passwords') then
			functions.saveToFile(values['username'],values['password'],'passwords')
			functions.lineClear()
			print('Created account for ',values['username'])
			verify=true
		end
		
		local msg=functions.ser({action='return',id=values['id'],value=verify})
		functions.sendMessage(parent_id,msg)
	-------------------------------------]	
	elseif values['value']=='login' then
	--[-----------------------------------
		if not functions.loadFromFile(values['username'],'sessions') then
			if functions.loadFromFile(values['username'],'passwords')==values['password'] then
				functions.lineClear()
				print('Logging in ',values['username'])
				functions.saveToFile(values['username'],values['id'],'sessions')
				verify=true
			end
		elseif values['id']==functions.loadFromFile(values['username'],'sessions') then
			verify=true
		end
		local msg=functions.ser({action='return',id=values['id'],value=verify,session=functions.loadFromFile(values['username'],'sessions')})
		functions.sendMessage(parent_id,msg)
	-------------------------------------]
	elseif values['value']=='session' then
	--[-----------------------------------
		user_id=functions.loadFromFile(values['username'],'sessions')
		verify=user_id==values['id']
		local msg=functions.ser({action='return',id=values['id'],value=verify,session_id=user_id,username=values['username']})
		functions.sendMessage(parent_id,msg)
		functions.lineClear()
		print('Send Message to ',values['id'])
	--------------------------------------]
	elseif values['value']=='logout' then
	--[------------------------------------
		if functions.loadFromFile(values['username'],'sessions')==values['id'] then
			functions.lineClear()
			print('Logging out ',values['username'])
			functions.saveToFile(values['username'],nil,'sessions')
			verify=true
		end
		
		local msg=functions.ser({action='return',id=values['id'],value=verify})
		functions.sendMessage(parent_id,msg)
	end
end

parent_id=getParentId()
header()
functions.createFile('config')
functions.createFile('passwords')
functions.createFile('sessions')
functions.saveToFile('Guest',false,'sessions')
parent_id=getParentId()


while true do
	local id,msg=functions.receiveMessage()
	manager(msg)
	local x,y=term.getCursorPos()
	term.setCursorPos(1,1)
	header()
	term.setCursorPos(x,y)
end

If necessary, the router code is here, and the master server code is here.
Bomb Bloke #2
Posted 18 February 2014 - 10:16 PM
I know a user could go through and change config and functions, and I want to make so that there is nothing they can do cause information to be sent to a unsecure source, or wrongly extract information.
Well, if you're using wireless, then anyone in range of the signal can tap into your communications. If wired, then anyone with access to your networking cable run can do the same.
Himself12794 #3
Posted 18 February 2014 - 10:23 PM
I know a user could go through and change config and functions, and I want to make so that there is nothing they can do cause information to be sent to a unsecure source, or wrongly extract information.
Well, if you're using wireless, then anyone in range of the signal can tap into your communications. If wired, then anyone with access to your networking cable run can do the same.
Well the way I set it up, when a router/client/server is first activated, it request the id of a parent router. In the case of a sub-server, it will only receive and send from that id. In the case of a router or master server, it only will do anything with a message that has correct values, so as to prevent crashes due to people randomly sending out messages. They also store a list of ids with registered computers.
I could have the client require to know the parent id as well, but I'm trying to make it so I can just spread the routers out throughout the world, and have some just pop in and attempt to connect, provided they have the correct OS.

The only broadcast I have is for a computer asking to join the newtwork, then everything else is based on stored ids after initial registration. I made the master server be able to act as a router as well, but I'm debating keeping this function.
CometWolf #4
Posted 19 February 2014 - 12:11 AM
That won't be secure at all. Rednet is just a simplified api for the modem api, which allowes you to chose what channel to send and receive on. The very same channels which rednet use for it's id system.
Himself12794 #5
Posted 19 February 2014 - 12:17 AM
That won't be secure at all. Rednet is just a simplified api for the modem api, which allows you to chose what channel to send and receive on. The very same channels which rednet use for it's id system.
I did not know that. However the only thing really that I have authentication for is whether or not you can delete a file. I will also assume that the only way to securely send information, then, will be by the use of rednet cables? In my case, the only compromised information would be what the client sends to the server in requesting to log in. Perhaps there is an encryption algorithm I could use?
Edited on 18 February 2014 - 11:19 PM
Bomb Bloke #6
Posted 19 February 2014 - 01:15 AM
Rednet cables or ComputerCraft's network cables, whatever, so long as no one can tap into them.

If people can tap into them, then (properly implemented) encryption would secure things, yes - assuming they can't get direct access the server machine, in which case all bets are off unless you rig up some rather complicated security directly on that unit (along the lines of "needs a password just to boot because everything on the system is encrypted"-type-security).

The best starting point is to figure out how many people are likely to want to break into your system, and where their knowledge levels are. You merely need to aim for a level of security that, for them, would be more trouble then it's worth to break through.
surferpup #7
Posted 19 February 2014 - 01:17 AM
I think it has been fairly well established that there is no such thing as security in ComputerCraft. Every system proposed thus far as workable in ComputerCraft presently can be defeated. Certainly some are more difficult to defeat than others, but all are vulnerable.

Edit: NINJA'd by [member='Bomb Bloke'] (That dude types so dang fast!!!)
Edited on 19 February 2014 - 12:18 AM
Himself12794 #8
Posted 19 February 2014 - 01:22 AM
Rednet cables or ComputerCraft's network cables, whatever, so long as no one can tap into them.

If people can tap into them, then (properly implemented) encryption would secure things, yes - assuming they can't get direct access the server machine, in which case all bets are off unless you rig up some rather complicated security directly on that unit (along the lines of "needs a password just to boot because everything on the system is encrypted"-type-security).

The best starting point is to figure out how many people are likely to want to break into your system, and where their knowledge levels are. You merely need to aim for a level of security that, for them, would be more trouble then it's worth to break through.

That's what I'm banking on. Right now this is mostly to just to see if I can actually finish this project, and then it's mostly for convenience. Really the only reason the passwords are there right now are to give some semblance of a network, and prevent someone from deleting a file he did not upload. Later I will add instant messaging and email, and that will require a bit more of security savy. I was actually just about to put what I've done so far in the OS section to see if I could get anyone to test it for me and give feedback.
Bomb Bloke #9
Posted 19 February 2014 - 06:58 AM
I think it has been fairly well established that there is no such thing as security in ComputerCraft. Every system proposed thus far as workable in ComputerCraft presently can be defeated. Certainly some are more difficult to defeat than others, but all are vulnerable.
Weeellll, that's only true to the point that it's true in the real world. The main differences have less to do with ComputerCraft and more to do with MineCraft.

If the "attack" involves "walking into your base and pickaxing the computer", then odds are the same tactic would be just as effective in real life. People are just more likely to walk into other people's houses with pickaxes in MineCraft then they are in reality (let alone with the intention of hitting things with them!). Likewise for "delete everything on the drive" attacks - on your average consumer computer, even firmware passwords are only a stalling tactic against those. Gimme five minutes and a screwdriver and your data is gone.

In terms of "software" security, however, it's perfectly possible to lock a ComputerCraft computer down to the point where hackers can't even determine what it's supposed to do (let alone extract any personal data from it). For eg, rig up a system that has one plain-text script on it which asks for an encryption key before decrypting everything else as needed (executable files, data files, whatever). Store everything decrypted in RAM only, write nothing back to the drive without re-applying encryption. Done.

Bear in mind that decent encryption methods aren't feasible to break regardless as to whether their source code is available; it all comes down to correct implementation.