{"action":"created","issue":{"url":"https://api.github.com/repos/Z-Wave-Me/z-way-issues/issues/83","labels_url":"https://api.github.com/repos/Z-Wave-Me/z-way-issues/issues/83/labels{/name}","comments_url":"https://api.github.com/repos/Z-Wave-Me/z-way-issues/issues/83/comments","events_url":"https://api.github.com/repos/Z-Wave-Me/z-way-issues/issues/83/events","html_url":"https://github.com/Z-Wave-Me/z-way-issues/issues/83","id":116945623,"number":83,"title":"Zway server stores plaintext passwords","user":{"login":"maros","id":82946,"avatar_url":"https://avatars.githubusercontent.com/u/82946?v=3","gravatar_id":"","url":"https://api.github.com/users/maros","html_url":"https://github.com/maros","followers_url":"https://api.github.com/users/maros/followers","following_url":"https://api.github.com/users/maros/following{/other_user}","gists_url":"https://api.github.com/users/maros/gists{/gist_id}","starred_url":"https://api.github.com/users/maros/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maros/subscriptions","organizations_url":"https://api.github.com/users/maros/orgs","repos_url":"https://api.github.com/users/maros/repos","events_url":"https://api.github.com/users/maros/events{/privacy}","received_events_url":"https://api.github.com/users/maros/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-11-14T19:06:42Z","updated_at":"2015-11-14T21:21:26Z","closed_at":null,"body":"automation/storage/configjson-XXX.json contains the plaintext user password. This is certainly not a good idea."},"comment":{"url":"https://api.github.com/repos/Z-Wave-Me/z-way-issues/issues/comments/156746869","html_url":"https://github.com/Z-Wave-Me/z-way-issues/issues/83#issuecomment-156746869","issue_url":"https://api.github.com/repos/Z-Wave-Me/z-way-issues/issues/83","id":156746869,"user":{"login":"maros","id":82946,"avatar_url":"https://avatars.githubusercontent.com/u/82946?v=3","gravatar_id":"","url":"https://api.github.com/users/maros","html_url":"https://github.com/maros","followers_url":"https://api.github.com/users/maros/followers","following_url":"https://api.github.com/users/maros/following{/other_user}","gists_url":"https://api.github.com/users/maros/gists{/gist_id}","starred_url":"https://api.github.com/users/maros/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maros/subscriptions","organizations_url":"https://api.github.com/users/maros/orgs","repos_url":"https://api.github.com/users/maros/repos","events_url":"https://api.github.com/users/maros/events{/privacy}","received_events_url":"https://api.github.com/users/maros/received_events","type":"User","site_admin":false},"created_at":"2015-11-14T21:21:26Z","updated_at":"2015-11-14T21:21:26Z","body":"True, if you have access to the file then you can change the password - but that's not the reason for filing an issue here. I mainly have two concerns\r\n\r\n* if i create a backup of the automation system then it would also contain the plaintext password. everybody with access to the backup files could login in the zway system \r\n* users tend to re-use one password for multiple systems. Everybody with access (even people with rightful access to the host running zway) a zway system could exploit this and try the passwords from other users against other services \r\n\r\nI agree that unsalted md5 passwords do not make a whole lot of sense. Instead I propose to store bcrypted passwords. There are plenty of JavaScript libraries for calculating bcrypt hashes (eg. https://github.com/nevins-b/javascript-bcrypt ).\r\n\r\nHere's some pseudo-code how a bcrypt password check could look like:\r\n\r\n```\r\nconstant currentCost = 10;\r\nif (storedPassword matches '$2a$(\\d+)$(.+)') {\r\n    // Get cost from stored password\r\n    storedCost = regexpMatch.1\r\n    // Calculate hash for comparison\r\n    calculatedHash = bcryptHash(userProvicedPassword,storedCost)\r\n    // Check hash\r\n    if (calculatedHash notequals storedPassword) {\r\n        return HTTP_403\r\n    }\r\n    // Compare costs\r\n    if (storedCost < currentCost) {\r\n        hashedPassword = bcryptHash(userProvicedPassword,currentCost)\r\n        storePassword(hashedPassword)\r\n    }\r\n    return HTTP_200\r\n} else {\r\n    // Password in plaintext (not yet bcrypted or manually reset by admin)\r\n    if (userProvicedPassword equals userStoredPassword) {\r\n        hashedPassword = bcryptHash(userProvicedPassword,currentCost)\r\n        storePassword(hashedPassword)\r\n        return HTTP_200\r\n    } else {\r\n        return HTTP_403\r\n    }\r\n}\r\n```"}}