OpenPGP подписано съдържание в XHTML

Версия 1.2.1, 19 юни 2008

Веселин Колев, Софийски Университет "Св. Климент Охридски"

Адрес за кореспонденция: vesso AT vesselin.org

Първоизточник: http://www.vesselin.org

Лиценз на документа: CC Attribution-ShareAlike

 

Съдържание:

  1. Увод

  2. Логическа схема на подписване на XHTML съдържание и използвани елементи

  3. Влагане на хеш суми в елемента IMG

  4. Разделяне на изходния XHTML код на шаблони

  5. Подписване на шаблона на съдържанието

  6. Конструиране на XHTML документа с подписано съдържание

  7. Проверка на валидността на електронния подпис с GnuPG

  8. Аспекти на сигурността на предлаганата схема за подписване

  9. Благодарности

  10. Предишни версии на публикацията

 

1. Увод

Електронното подписване на XHTML документи решава проблема за автентичността на съдържанието, който не може да бъде решен чрез протокола SSL (използван в HTTPS). При една HTTPS сесия се удостоверяват само страните, обменящи си документи, но не и самите документи. Казано по друг начин, SSL удостоверява и защитава сесията за пренос на данни, но не удостоверява самите данни, а само указва, че техния поток идва от определен, удостоверен, източник.

Този документ има за цел да опише един възможен начин за OpenPGP подписване на съдържанието на XHTML документи с цел удостоверяване на съдържанието им. Начинът на извършване на подписването, описан по-долу, засяга само съдържанието, което се намира в елемента BODY и не обхваща това в елементите XML, HTML, HEAD и др. Реално погледнато, съдържанието в BODY е визуалното съдържание, което потребителя вижда и обработва (например отпечатва). Следователно неговото подписване решава задачата за проверка на източника на информацията в BODY. Документът няма претенциите за първичност, нито описва добра практика. Той само описва едно възможно решение, което трябва да се прилага само в случаите, в които има ясно разбиране за приложимостта му. В Интернет има документи, които описват подписването на HTML документи, но те или не отчитат XHTML синтаксиса, или с тяхна помощ не е възможно да се получи валидируем изходен код на подписаната страница със съдържание.

Описанието в документа съблюдава правилността на XHTML синтаксиса и метода на подписване на съдържанието е такъв, че да позволява изработването на валиден XHTML 1.0 Strict и XHTML 1.1 код на подписаните страници.

 

2. Логическа схема на подписване на XHTML съдържание и използвани елементи

Потребителят възприема като документ това съдържание от един XHTML документ, което софтуера визуализира и което той може да отпечати. На практика винаги това е съдържанието в елемента BODY. Останалите части на XHTML документа съдържат служебна информация, която не е визуална. Следователно електронното подписване трябва да засегне именно тази част от съдържанието на документа. В огромното количество от случаи, това е напълно достатъчно. Как обаче да се реализира подписването на съдържанието в BODY.

При повечето публикувани в Интернет схеми за електронно подписване на HTML документи, цялата или части от OpenPGP информацията в Base64 формат, се визуализират, което е ненужно от потребителска гледна точка, защото потребителя се интересува само от това дали подписът се валидира или не (няма да споменаваме, че подобно форматиране често нарушава валидността дори на такъв свободен и нестрог синтаксис, като този на езика HTML). За потребителят е невъзможно да анализира визуално информацията в Base64 формат, която му се предлага без негова воля при споменатите по-горе решения. Подобен анализ може да се извърши само от софтуер. Именно по тази причина е по-уместно цялата OpenPGP информация, вложена в документа, да остава скрита в XHTML кода, т.е. да е поместена в невизуален елемент по такъв начин, че да може да бъде четена само от софтуер за валидация на електронния подпис.

Един елемент, който предлага такава функционалност е елемента SCRIPT. Той може да помести в себе си "inline" форматната информация на OpenPGP подписа в Base64 формат. Изборът на елемент за коментар е неудачен избор в XHTML и затова той няма да бъде дискутиран. Удобството на SCRIPT е, че допуска MIME типизация на съдържанието. Следователно може да се укаже такъв MIME тип на съдържанието в SCRIPT, който да не ангажира визуализиращия софтуер с никакво изпълнение на скрипт. Такъв MIME тип е "text/plain". По този начин, структура от типа:

...
<script type="text/plain">
	...
</script>
...

може да помества в себе си произволна по съдържание текстова информация, включително и "inline" информацията от OpenPGP подписването.

За подписването на съдържанието в BODY са нужни две такива структури. Едната трябва да включва в себе си декларация за начало на OpenPGP подписан блок, а другата да декларира края му и да опише електронния подпис и метаданните към него:

...
<script type="text/plain">
- - -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
</script>
...
<script type="text/plain">
- - -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)

iQIVAwUBRxnxBrafyWmgOHdbAQqnPA//d53mu4qeFYP+kT9oMvLgVcGLpV6eHP1Z
HkeD1GhDD85Ya69LfOHoxD8iVzeQuwfwG75BXosGzLsgSSggrW2pEktWwNEq+etL
bfjgeBgA1ncPmq9QlaA38d703DXjQ+YAQvK1c+ZKu/3CLJa+bzpnQVSUYZE3WB0G
njJR1Z6smuQGyTKDybAHI16mnC5g0ejdthxSdAK5+rCUQMvrIvXwODtrYr6ZvUJf
09L06bQwpZoN7BkCC2YHAfJSi1IJypQW2sP8Z69R+OWVRa1MQxlqpkU/eB7qO9Dm
FQwSdyEhk9OjTR6u265uwusJUH3fdEEnMlNijubM6HJ4/0wl3hvy1dScvE/uQK2J
yoQRo/v8KIhOgOlAldba+lgeDatsOCk7D+42KK1VgK7JCIzUEBWH8B779KpXBD/C
wqgCqOVr7tN1qZS5UWRxe1FF8WB0ZZgJ1Xh16vScZ5lCNQr9AOhcjScqgiqKsuAE
ftieHppPla4gbHFYHXTnZhIJdmVS7UdIjBqhHnBFSC824BuvCfr8FlxVTW3ObrA9
4TAoYXL/kaViZn7y2v/ZbP+j4DZp+XhjPXNlcsNVFHIz9bhNKXA1qbnVRby+RT6H
Oj4zbA8YGl/NfIbJow6yDvaIQd2oWJXuOXp7UhS9HvzZFzUoSIZpdRhA/5C3OOHk
KMrQjn0UK3s=
=0w0A
- - -----END PGP SIGNATURE-----
</script>
...

При извършването на подписването, се изготвя блок от съдържанието на елемента BODY, в който на първия ред се затваря един елемент SCRIPT (без да е отворен), а на последния се отваря елемент SCRIPT (без да се затваря). След подписването се отваря първия елемент SCRIPT и се затваря втория. Така се получава описаната по-горе структура. Тази структура е семантична. От гледна точка на валидацията на XHTML документа, тя е прозрачна и не засяга валидността на кода, от друга, софтуера, който проверява валидността на електронния подпис, анализира само тази структура, без значение на типа информация в нея и извън нея (в смисъла на XHTML елементи и съдържанието им).

 

3. Влагане на хеш суми в елемента IMG

Файловете с изображения, които се зареждат от клиентския софтуер, се намират в отделени от XHTML съдържанието файлове с бинарно съдържание. При подписване на XHTML съдържанието, няма как да извърши подписване и на съдържанието на файловете с изображенията в една стъпка и резултата да бъде един монолитен OpenPGP блок. Изходът е за всяко съдържание на файл с изображение, да се пресметне хеш сума и тя да се вложи някъде в XHTML съдържанието така, че да не нарушава валидността на синтаксиса. След като XHTML съдържанието с така вложените хеш суми се подпише, те стават автоматично електронни подписи на съдържанието на изображенията.

Най-подходящият начин за влагане на информация за хеш сумите на съдържанието на изображенията, е описането им като стойности на атрибута ID в елемента IMG. От друга страна е добре да се декларира и самата хеш функция, с която е пресметната хеш сумата, за да може след това автоматизирано и еднозначно сумата да бъде проверена. Следователно стойността на ID атрибута трябва да съдържа и името на хеш функцията. Един подходящ формат за указване на хеш функцията и хеш сумата е:

id="HASH_FUNCTION:HASH_VALUE"

например:

<img src="image.png" title="Image Name" width="88" height="31"
id="SHA256:8f60851388223c6fb0253e72308573cf96266fe9430ada5c383da7af0e93420f" />

Погледнато напълно строго, хеш сумата е наистина универсален идентификатор на дадено съдържание и съвсем справедливо тя може да се използва като стройност на атрибута ID.

След като стойността на хеш сумата бъде пресметната, съдържанието на изображението не трябва повече да бъде мофицирано, защото така ще се промени сумата и след това подписа върху него няма да е валиден.

Нужено е да се отбележи, че така не може да бъде подписвано съдържанието на изображения, които се влагат в атрибутите на елемента BODY. За тях може да се използва схема, при която те допълнително да се дефинират в комантар, който да се намира в елемента BODY.

 

4. Разделяне на изходния XHTML код на шаблони

Подписването се извършва след приключване на всякакви редакции по изходния XHTML код на документа. XHTML съдържанието се разделя по начин, описан в примера по-долу.

 

Примерен изходен код на XHTML документ, чието съдържание ще бъде електронно подписано:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="bg">

<head>
  <title>OpenPGP подписано съдържание</title>
</head>
<body>

<h4>OpenPGP подписано съдържание</h4>

<p>Съдържанието в елемента BODY подлежи на електронно подписване</p>

</body>
</html>

 

От изходния код се отделя шаблон на заглавната част:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="bg">

<head>
  <title>OpenPGP подписано съдържание</title>
</head>
<body>

 

и се извършва дооформянето му като се отваря елемент SCRIPT с описание на използвания MIME тип (в случая "text/plain"):

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="bg">

<head>
  <title>OpenPGP подписано съдържание</title>
</head>
<body>

<script type="text/plain">

 

Това е съдържанието между <body> и </body>. Именно това съдържание се визуализира от софтуера на потребителя. То се отделя от изходния код и се запазва в отделен файл (в примера по-долу това е файла unsigned_prototype.html). В началото му се затваря елемент SCRIPT, а в края му се отваря друг елемент SCRIPT. За конкретният пример, съдържанието, което подлежи на подписване е:

</script>

<h4>OpenPGP подписано съдържание</h4>

<p>Съдържанието в елемента BODY подлежи на електронно подписване</p>

<script type="text/plain">

 

Това е шаблонът, който следва след електронно подписания блок. В него не бива да има никакво подлежащо на визуализация съдържание. В началото му се затваря елемент SCRIPT. За конкретното изходно съдържание от примера, този шаблон има вида:

</script>

</body>
</html>

 

5. Подписване на шаблона на съдържанието

Подписването на шаблона на съдържанието става с инструмента GnuPG по следния примерен начин:

$ gpg -a --clearsign -o signed_prototype.html unsigned_prototype.html

Ако се следват наименованията на файлове от този пример, подписания шаблон ще се намира във файла signed_prototype.html. Съдържанието на този файл не бива да бъде модифицирано по никакъв повод, защото всяка негова модификация би провалила валидността на електронния подпис.

 

6. Конструиране на XHTML документа с подписано съдържание

След като шаблона на съдържанието бъде електронно подписан, може да се пристъпи към конструиране на крайния вид на XHTML документа. Най-лесния начин е ако в началото на файла signed_prototype.html се прибави шаблона на заглавната част, а в края затварящия шаблон. Присъединяването на шаблоните трябва да се извъшва внимателно, за да не се наруши/промени структурата на подписаното съдържание. Един примерен изглед на крайната конструкция на XHTML документа би изглеждал така:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="bg">

<head>
  <title>OpenPGP подписано съдържание</title>
</head>
<body>

<script type="text/plain">

- - -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

</script>

<h4>OpenPGP подписано съдържание</h4>

<p>Съдържанието в елемента BODY подлежи на електронно подписване</p>

<script type="text/plain">

- - -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)

iQIVAwUBRxnxBrafyWmgOHdbAQqnPA//d53mu4qeFYP+kT9oMvLgVcGLpV6eHP1Z
HkeD1GhDD85Ya69LfOHoxD8iVzeQuwfwG75BXosGzLsgSSggrW2pEktWwNEq+etL
bfjgeBgA1ncPmq9QlaA38d703DXjQ+YAQvK1c+ZKu/3CLJa+bzpnQVSUYZE3WB0G
njJR1Z6smuQGyTKDybAHI16mnC5g0ejdthxSdAK5+rCUQMvrIvXwODtrYr6ZvUJf
09L06bQwpZoN7BkCC2YHAfJSi1IJypQW2sP8Z69R+OWVRa1MQxlqpkU/eB7qO9Dm
FQwSdyEhk9OjTR6u265uwusJUH3fdEEnMlNijubM6HJ4/0wl3hvy1dScvE/uQK2J
yoQRo/v8KIhOgOlAldba+lgeDatsOCk7D+42KK1VgK7JCIzUEBWH8B779KpXBD/C
wqgCqOVr7tN1qZS5UWRxe1FF8WB0ZZgJ1Xh16vScZ5lCNQr9AOhcjScqgiqKsuAE
ftieHppPla4gbHFYHXTnZhIJdmVS7UdIjBqhHnBFSC824BuvCfr8FlxVTW3ObrA9
4TAoYXL/kaViZn7y2v/ZbP+j4DZp+XhjPXNlcsNVFHIz9bhNKXA1qbnVRby+RT6H
Oj4zbA8YGl/NfIbJow6yDvaIQd2oWJXuOXp7UhS9HvzZFzUoSIZpdRhA/5C3OOHk
KMrQjn0UK3s=
=0w0A
- - -----END PGP SIGNATURE-----

</script>

</body>
</html>

Така изготвеният XHTML документ е вече готов за публикуване и проверка.

 

7. Проверка на валидността на електронния подпис с GnuPG

След като подписаният документ бъде изтеглен и записан върху локалната файлова система, проверката за валидност на електронния подпис, може да бъде извършена с инструмента GnuPG по следния начин:

$ gpg --verify signed_document.html

За да може проверката да даде смислен разултат, OpenPGP сертификата (публичния ключ) на субекта, подписал документа, трябва да е наличен в локалното хранилище на GnuPG. За аспекти на сигурността по удостоверяването на валидността на подписания документ, виж следващата точка от статията.

 

8. Аспекти на сигурността на предлаганата схема за подписване

При използването на тази схема съществува принципен проблем, който изисква проверяващия подписа да има опит в OpenPGP, inline подписване и знания за HTML и XHTML. Проблемът не е в самата схема, а във визуализацията на документа от страна на визуализиращия софтуер. Може да се направи така, че в един HTML/XHTML документ да се вложи друг и така да се визуализира не подписаното съдържание, а някакво друго, в общия случай злонамерено. Особена опасност създава използването на javascript като вложен елемент SCRIPT преди елемента SCRIPT за начало на подписването.

Ето пример за създаване на злонамерена визуализация:

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <title>Тест</title>
</head>
<body>

<p> Това е прибавен текст </p>

</body>
</html>

<head>
<script type="text/plain">

- - -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

</script>
  <title>Тест</title>
</head>
<body>

<p> Това е подписан текст </p>

<script type="text/plain">

- - -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)

iQIVAwUBRxnxBrafyWmgOHdbAQqnPA//d53mu4qeFYP+kT9oMvLgVcGLpV6eHP1Z
HkeD1GhDD85Ya69LfOHoxD8iVzeQuwfwG75BXosGzLsgSSggrW2pEktWwNEq+etL
bfjgeBgA1ncPmq9QlaA38d703DXjQ+YAQvK1c+ZKu/3CLJa+bzpnQVSUYZE3WB0G
njJR1Z6smuQGyTKDybAHI16mnC5g0ejdthxSdAK5+rCUQMvrIvXwODtrYr6ZvUJf
09L06bQwpZoN7BkCC2YHAfJSi1IJypQW2sP8Z69R+OWVRa1MQxlqpkU/eB7qO9Dm
FQwSdyEhk9OjTR6u265uwusJUH3fdEEnMlNijubM6HJ4/0wl3hvy1dScvE/uQK2J
yoQRo/v8KIhOgOlAldba+lgeDatsOCk7D+42KK1VgK7JCIzUEBWH8B779KpXBD/C
wqgCqOVr7tN1qZS5UWRxe1FF8WB0ZZgJ1Xh16vScZ5lCNQr9AOhcjScqgiqKsuAE
ftieHppPla4gbHFYHXTnZhIJdmVS7UdIjBqhHnBFSC824BuvCfr8FlxVTW3ObrA9
4TAoYXL/kaViZn7y2v/ZbP+j4DZp+XhjPXNlcsNVFHIz9bhNKXA1qbnVRby+RT6H
Oj4zbA8YGl/NfIbJow6yDvaIQd2oWJXuOXp7UhS9HvzZFzUoSIZpdRhA/5C3OOHk
KMrQjn0UK3s=
=0w0A
- - -----END PGP SIGNATURE-----

</script>

</body>
</html>
		

Този изходен код е неверен синтактично, но ще се визуализира от софтуера за визуализация така:

	Това е прибавен текст
	Това е подписан текст

Евентуално съмнение за вложен код би бил проблем с валидацията на документа през валидатор за XHTML код. За да се потвърди съмнението обаче, се изисква предварителна увереност, че оригиналния код е бил валидируем, преди да е променен злонамерено, което не винаги е така. Масово се пише изходен XHTML код без той да се проверява за валидност.

Най-общо казано, за да се работи с OpenPGP подписани документи, трябва проверяващия електронния подпис да има познания по HTML/XHTML, OpenPGP и inline подписване. Ако методът трябва да се сведе на ниво "обикновен потребител", трябва да се помисли за използване на приложение, което да визуализира подписаната част от документа.

 

Благодарности

Авторът изразява благодарност на Пейо Попов и Калоян Доганов за проведената дискусия относно изложената идея за подписване и нейната реализация. Благодаря на Георги Гунински за продължителната и полезна дискусия относно сигурността на метода.

 

10. Предишни версии на публикацията.

 

Този документ е с OpenPGP подписано съдържание
[информация] [електронен подпис][TimeStamp]

Creative Commons - Признание 2.5 Valid CSS! Valid XHTML 1.0 Strict