Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #11 (permalink)  
Старый 09.04.2019, 20:16
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

Сообщение от loutston
Благодарю за отсутствие помощи, разобрался в коде самостоятельно, это было проще чем казалось.
Как вы её решили?
Ответить с цитированием
  #12 (permalink)  
Старый 11.04.2019, 13:18
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

Сообщение от laimas
Где сама защищенная страница до поры до времени, на сервере? Вот на сервер и передавайте "abc123", которое он сравнит с хешем этого пароля. В этом случае подобрать будет очень сложно.
Давайте внимательно посмотрим на вашу схему. Ваша схема должна использовать две страницы. Один для входа в систему, второй для секретной страницы.

Но это большая уязвимость безопасности, если не существует единственного четкого способа доступа к данным вашего приложения. Я не говорю о коде, который я написал таким образом, я думаю, что он должен работать, но кажется, что существует второй способ доступа. Вам нужно два, это нормально, но не более того числа, которое вы предполагаете. Допустим, вы просто перенаправляете своего пользователя на секретную страницу, если предоставленные учетные данные верны. Да, ваши пользователи могут даже не знать, что можно получить секретную страницу, просто вставив правильный адрес в адресную строку, но ничто не мешает поисковому боту Google проиндексировать эту страницу.

На самом деле я нашел вашу идею в одном приложении для камер системы безопасности, которое было разработано так, как вы описали ... люди верили, что они защищены, но на самом деле эта "защищенная" страница была доступна всем, кто делает правильный поисковый запрос.

Я думаю, было бы излишне делать две страницы для этого приложения викторины.

В любом случае, вы можете написать свое решение полностью на JavaScript. В современных браузерах есть API веб-криптографии. Почему бы не использовать это? Таким образом, вы можете создать свое приложение, в котором хранятся вопросы и ответы на вопросы викторины, а также данные, которые будут показаны кому-то, кто прошел тест.

<script>

	var data = {
		quiz: {cipherText:"kqiyEf7WQl9774pyF3PI2w4gmpt0yZDtESUfgNyKaItOvJWzzKBGdLu5q2d9fO2CDlMPldGXJCesA9w7CE73S53hE25HWQSTYuqTZ69tVeQBix4N8QS+8lec8l1ZHawBele5l8A/4Smie77p9sJCakFcF/WYYy1iJJ93UlNzmc00TS7kTOA71D8zYthR/xnfBrnmuwrACgJN+kyUtnpHXKRpuCoicn+NqD2xm63HpbTJnME9Ns/BStttyyWtoYCKvuaB9ZpQYyM5BAR+w0liTiicrawkFslnpTVwY9MqhkNeEq7GZgYkKSXiJmP3H50BVBeozZWSW3lGxJhAk9TVnoQRIvhzP7DqX7NPbL5GUqY8HciSDfwBwPAtPBGBfdP62MZRnFpnW9X7Fmt7tdW4CaaMzjCL2+tg5y5T7GKK0ymgxmohuqRiQnuriOVTxcDAQwNkW2ntZYo+RxU9X2ONiEOienc5SSqGAivNOfReU5UcUJj+8FslyCXhL6AeinxjG9Kis0uVvHKKUMyawM3cT9t3BH1shoVB1e37mJ6g1QKlyUd0VwY8sBqW5TZdCWFJjB65YcicibBEbciXIWcUbUDRqKyS0w==",iv:"CGE/wWm0eEJzWzKu"},
		code: {cipherText:"pNavP6FL6bCxtB9D6fVXhFqRJXWOw/XkCHLohPcWclrYwstm9Rd+NOrtTCAFU7bpDN5VD8wjc9V1gNZpLRAzhfi0kw==",iv:"F6tJKgxCXPveHGYq"}
	};

class App {
	constructor() {}

	async start(encrypted) {
		class State {
			constructor(points) {
				this.points = points;
				Object.freeze(this);
			}
		}
		try {
			const popQuiz = await this.decrypt(encrypted.quiz, () => prompt("Password:", ""));
			var rightAnswers = 0;
			var answers = [];

			alert("Добро пожаловать в викторину!");

			questions: for(const { question, answer } of popQuiz) {
				do {
					var guess = prompt(question);

					if(guess == null) break questions;

					if((await this.hash(guess)) === answer) {
						rightAnswers++;
						answers.push(answer);
						continue questions;
					}
				} while(confirm("Ответ неверен! Попробовать ещё?"));

				break;
			}

			if(rightAnswers === popQuiz.length) {
				var message;
				try {
					message = await this.decrypt(encrypted.code, () => JSON.stringify(answers));
				} catch(error) {}
			}

			alert(`Пройдено ${rightAnswers} из ${popQuiz.length}\n${message ? message : "Чтобы получить расширенный доступ, вы должный пройти тест!"}`);
		} catch(error) {
			console.log(error);
			if(confirm("Авторизация не удалась! Попробовать ещё раз?")) {
				this.start(encrypted);
			}
		}
	}

	static hash(algo, str) {
		return crypto.subtle.digest(algo, new TextEncoder().encode(str));
	}

	static async genEncryptionKey(password, mode, length) {
		var algo = {
			name: 'PBKDF2',
			hash: 'SHA-256',
			salt: new TextEncoder().encode('a-unique-salt'),
			iterations: 1000
		};

		var derived = { name: mode, length: length };
		var encoded = new TextEncoder().encode(password);
		var key = await crypto.subtle.importKey('raw', encoded, { name: 'PBKDF2' }, false, ['deriveKey']);
	
		return crypto.subtle.deriveKey(algo, key, derived, false, ['encrypt', 'decrypt']);
	}

	static async encrypt(text, password, mode, length, ivLength) {
		var algo = {
			name: mode,
			length: length,
			iv: crypto.getRandomValues(new Uint8Array(ivLength))
		};
		var key = await this.genEncryptionKey(password, mode, length);
		var encoded = new TextEncoder().encode(text);

		return {
			cipherText: await crypto.subtle.encrypt(algo, key, encoded),
			iv: algo.iv,
			toJSON() {
				return {
					cipherText: App.encode64(this.cipherText),
					iv: App.encode64(this.iv)
				};
			}
		};
	}

	static async decrypt(encrypted, password, mode, length) {
		var algo = {
			name: mode,
			length: length,
			iv: encrypted.iv
		};
		var key = await this.genEncryptionKey(password, mode, length);
		var decrypted = await crypto.subtle.decrypt(algo, key, encrypted.cipherText);

		return new TextDecoder().decode(decrypted);
	}

	static encode64(buff) {
		return btoa(new Uint8Array(buff).reduce((s, b) => s + String.fromCharCode(b), ""));
	}

	async encrypt(object, passwordCallback) {
		var mode = 'AES-GCM', length = 256, ivLength = 12;
		var encrypted = await App.encrypt(JSON.stringify(object), passwordCallback(), mode, length, ivLength);
		return encrypted.toJSON();
	}

	async decrypt(object, passwordCallback) {
		var mode = 'AES-GCM', length = 256, ivLength = 12;

		function toBuffer(encrypted, property) {
			return fetch(`data:text/plain;base64,${encrypted[property]}`).then(r => r.arrayBuffer());
		}

		var encrypted = {
			cipherText: await toBuffer(object, "cipherText"),
			iv: new Uint8Array(await toBuffer(object, "iv"))
		};

		var decrypted = await App.decrypt(encrypted, passwordCallback(), mode, length);
		return JSON.parse(decrypted);
	}

	async hash(string) {
		var hashed = await App.hash('SHA-256', `#DATA<${string}>`);
		return App.encode64(hashed);
	}
}

var app = new App();

</script>
<button onclick="app.start(data);">Начать викторину для избранных!</button>

Последний раз редактировалось Malleys, 11.04.2019 в 18:50.
Ответить с цитированием
  #13 (permalink)  
Старый 11.04.2019, 14:14
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,134

Malleys,
спасибо за код(концепция понятна), жаль только знаний маловато, не могу его ни дополнить, ни использовать.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
смена пароля ElshStephan Элементы интерфейса 8 15.06.2015 13:59
Минимальная длинна пароля Mizter Egoist Элементы интерфейса 3 18.04.2014 16:38
Валидация Пароля и Email 203 Элементы интерфейса 4 26.05.2013 15:44
Кодировка внешнего JS файла - проблема в Chrome Freddis Opera, Safari и др. 3 26.07.2011 21:48
кодировка UTF-8 в IE6 Александр345 (X)HTML/CSS 1 14.06.2011 14:25