Реализация на javascript
(0 чел.) 
  • Страница:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

ТЕМА: Реализация на javascript

Re: Реализация на javascript 1 год, 9 мес. назад #3406

  • Rustem2016
  • Давно я тут
  • Постов: 93
  • Репутация: 5
Что-то типа доверенной площадки для подписания?! Это может потребовать изменения в НПА, гарантирующие и обязывающие данные действия со стороны pki.gov.kz.

Re: Реализация на javascript 1 год, 8 мес. назад #3562

  • vprokof
  • Осваиваюсь на форуме
  • Постов: 28
  • Репутация: 0
“Это решение ужасное, но а какое у вас решение есть?”
Про NCALayer
2015 г.

- Какие будут ваши доказательства?
Идёт модернизация настольной системы, требуется возможность работы в Интернет, система переписывается на PHP. В системе есть аутентификация пользователей и подпись контента по ЭЦП. Технический специалист чувствует боль пользователей настольных систем, которые мучаются с эксплуатацией NCALayer и печаль отрезанных мобильных пользователей, количество которых уже приближается к 80 процентам. Скачав пару библиотек на JavaScript и убедившись, что NCALayer на клиенте можно заменить JavaScript скриптами, технический специалист идёт показывать это решение административному специалисту и обнаруживает проблему. Доказать, что 400 КБ кода, взятые из сети Интернет, решают задачу аутентификации и подписания посредством ЭЦП, без авторитетных государственных структур технический специалист административному специалисту не может.

- Если не получается вертикально и горизонтально – делаем диагонально.
Чисто настольный вариант через NCALayer и чисто интернет вариант через JavaScript не устраивают. Остаётся компромиссный вариант – читать ключи на клиенте и проверять их на сервере. Попробуем аргументировать такое решение.
1) ЭЦП ключи можно угнать.
Ключи можно угнать и в настольном приложении NCALayer. Делаем защищённое SSL соединение с зелёным https и большинство пользователей уже будут доверять такому сайту. Можно зарегистрировать предприятие сайта в картотеке DUNS или D-U-N-S en.wikipedia.org/wiki/Data_Universal_Numbering_System и отправлять туда особых скептиков.

2) SSL ключи дорого стоят и устанавливать их сложно.
Выход есть. Let’s Encrypt letsencrypt.org/ — центр сертификации предоставляет бесплатные криптографические сертификаты X.509 для TLS шифрования (HTTPS). Процесс выдачи сертификатов полностью автоматизирован.

3) На PHP нет библиотек для работы с ключами GOST.
Читаем контейнер с ключами, переводим его в base64 и по защищённому https:// каналу отправляем на сервер на проверку. На сервере реализуем PHP/Java Bridge.
php-java-bridge.sourceforge.net/pjb/contact.php
nikita-petrov.com/articles/o-tom-kak-podruzhit-java-i-php
На лету в java проверяем сертификат на:
- правильность атрибутов сертификата, например период действия, политики
- соответствие цепочке сертификатов
- отсутствие сертификата в списке отозванных ключей
На лету подписываем данные необходимыми ключами.
Никаких следов ЭЦП на сервере не останется даже при сбоях в середине процесса.

В результате:
- Пользователи могут работать на всех устройствах, на которых можно прочитать файл.
- Административный специалист видит зелёный https://
- Технический специалист по сертификации систем видит библиотеку НУЦ.

Если можно что-то улучшить, критические замечания приветствуются.
Сырой код на Java для PHP/Java Bridge прикладывается.



/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package xmlsign;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;

import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;

import java.security.Security;

import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.security.cert.X509CRL;
import java.security.cert.X509Extension;
import java.security.cert.X509CertSelector;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.CertPathBuilder;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.CertStore;

import java.util.Enumeration;
import java.util.Base64;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import kz.gov.pki.kalkan.asn1.pkcs.PKCSObjectIdentifiers;
import kz.gov.pki.kalkan.jce.provider.KalkanProvider;
import kz.gov.pki.kalkan.xmldsig.KncaXS;

import org.apache.xml.security.encryption.XMLCipherParameters;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.security.cert.CertificateFactory;
import java.io.FileInputStream;

/**
 *
 * 
 */
public class XMLSign {

    /**
     * @param args the command line arguments
     */
       public static void main(String[] args) {
            String xml64 = "...";
            /*String xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                    + "<root>"
                    + "<person id=\"someid\">"
                    + "<name>Стеве Жобс</name>"
                    + "<iin>123456789012</iin>"
                    + "</person>"
                    + "</root>";
//System.out.println("Hello World!");
            XMLSign object = new XMLSign();
            String signedXml = object.signBase64XML(xml64, "123456", xmlString);
            object.verifyXml(signedXml);*/
            XMLSign object = new XMLSign();
            //Boolean checkedCRLErrors = object.checkCRL(xml64, "123456");
            
        }
     
    public Boolean checkCRL(String cert64, String password, String pathCa, String pathNca, String pathCrl, String pathRcrl) {
        try {
            // Получаем сертификат
            Provider provider = new KalkanProvider();
            Security.addProvider(provider);
            KncaXS.loadXMLSecurity();
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
           
            KeyStore store = KeyStore.getInstance("PKCS12", provider.getName());

            // Здесь было чтение ключа из файла, сейчас читаем из base64
            byte[] data = Base64.getDecoder().decode(cert64);
            InputStream inputStream = new ByteArrayInputStream(data);

            store.load(inputStream, password.toCharArray());
            Enumeration<String> als = store.aliases();
            String alias = null;
            while (als.hasMoreElements()) {
                alias = als.nextElement();
            }
            X509Certificate cert = (X509Certificate) store.getCertificate(alias);
            
            // Дальше проверяем его на отозванность
            CertificateFactory cf = CertificateFactory.getInstance("X.509", provider);
            X509Certificate ca = (X509Certificate) cf.generateCertificate(new FileInputStream (pathCa));
            ca.checkValidity();
            X509Certificate nca = (X509Certificate) cf.generateCertificate(new FileInputStream (pathNca));

            X509CRL crl = (X509CRL) cf.generateCRL(new FileInputStream (pathCrl));
            X509CRL rcrl = (X509CRL) cf.generateCRL(new FileInputStream (pathRcrl));
            
            ArrayList<X509Extension> list = new ArrayList<X509Extension>();
            list.add(nca);
            list.add(cert);
            list.add(crl);
            list.add(rcrl);
            CollectionCertStoreParameters certStoreParameters = new CollectionCertStoreParameters(list);
            CertStore certStore = CertStore.getInstance("Collection", certStoreParameters, provider);
            CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", provider);
            // проверка до корневого CA, можно сократить до промежуточного NCA
            
            TrustAnchor anchor = new TrustAnchor(ca, null);
            Set<TrustAnchor> anchors = new HashSet<TrustAnchor>();
            anchors.add(anchor);
            X509CertSelector selector = new X509CertSelector();
            // задаем параметры для селектора конечного сертификата или можно указать полное соответствие сертификата
            //selector.setSerialNumber(cert.getSerialNumber());
            //selector.setIssuer(cert.getIssuerX500Principal());
            selector.setCertificate(cert);
            PKIXBuilderParameters builderParameters = new PKIXBuilderParameters(anchors, selector);
            // если не добавляли список CRL, то надо отключить проверку
            builderParameters.setRevocationEnabled(false);
            builderParameters.addCertStore(certStore);
            builderParameters.setSigProvider(provider.getName());
            PKIXCertPathBuilderResult builderResult = (PKIXCertPathBuilderResult) builder.build(builderParameters);
            System.out.println(builderResult);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
   
    //Подписываем XML
    public String signBase64XML(String cert64, String password, String xmlString) {

        String result = null;

        try {

            Provider provider = new KalkanProvider();
            Security.addProvider(provider);
            KncaXS.loadXMLSecurity();
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
            final Document doc = documentBuilder.parse(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));
            final String signMethod;
            final String digestMethod;
            KeyStore store = KeyStore.getInstance("PKCS12", provider.getName());
            
            // Здесь было чтение ключа из файла, сейчас читаем из base64
            byte[] data = Base64.getDecoder().decode(cert64);
            InputStream inputStream = new ByteArrayInputStream(data);
            
            store.load(inputStream, password.toCharArray());
            Enumeration<String> als = store.aliases();
            String alias = null;
            while (als.hasMoreElements()) {
                alias = als.nextElement();
            }

            final PrivateKey privateKey = (PrivateKey) store.getKey(alias, password.toCharArray());
            final X509Certificate x509Certificate = (X509Certificate) store.getCertificate(alias);
            String sigAlgOid = x509Certificate.getSigAlgOID();
            if (sigAlgOid.equals(PKCSObjectIdentifiers.sha1WithRSAEncryption.getId())) {
                signMethod = Constants.MoreAlgorithmsSpecNS + "rsa-sha1";
                digestMethod = Constants.MoreAlgorithmsSpecNS + "sha1";
            } else if (sigAlgOid.equals(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId())) {
                signMethod = Constants.MoreAlgorithmsSpecNS + "rsa-sha256";
                digestMethod = XMLCipherParameters.SHA256;
            } else {
                signMethod = Constants.MoreAlgorithmsSpecNS + "gost34310-gost34311";
                digestMethod = Constants.MoreAlgorithmsSpecNS + "gost34311";
            }

            XMLSignature sig = new XMLSignature(doc, "", signMethod);

            if (doc.getFirstChild() != null) {
                doc.getFirstChild().appendChild(sig.getElement());
                Transforms transforms = new Transforms(doc);
                transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
                transforms.addTransform(XMLCipherParameters.N14C_XML_CMMNTS);
                sig.addDocument("", transforms, digestMethod);
                sig.addKeyInfo(x509Certificate);
                sig.sign(privateKey);
                StringWriter os = new StringWriter();
                TransformerFactory tf = TransformerFactory.newInstance();
                Transformer trans = tf.newTransformer();
                trans.transform(new DOMSource(doc), new StreamResult(os));
                os.close();
                result = os.toString();
            }

            System.err.println(result);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }  
    
    //Проверяем валидность XML
    public boolean verifyXml(String xmlString) {
        boolean result = false;
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
            Document doc = documentBuilder.parse(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));

            Element sigElement = null;
            Element rootEl = (Element) doc.getFirstChild();

            NodeList list = rootEl.getElementsByTagName("ds:Signature");
            int length = list.getLength();
            for (int i = 0; i < length; i++) {
                Node sigNode = list.item(length - 1);
                sigElement = (Element) sigNode;
                if (sigElement == null) {
                    System.err.println("Bad signature: Element 'ds:Reference' is not found in XML document");
                }
                XMLSignature signature = new XMLSignature(sigElement, "");
                KeyInfo ki = signature.getKeyInfo();
                X509Certificate cert = ki.getX509Certificate();
                if (cert != null) {
                    result = signature.checkSignatureValue(cert);
                    rootEl.removeChild(sigElement);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.err.println("VERIFICATION RESULT IS: " + result);
        return result;
    }

    
}


Изменено: 1 год, 8 мес. назад от vprokof.
Спасибо сказали: art

Re: Реализация на javascript 1 год, 8 мес. назад #3565

  • tjunussov
  • Новый участник
  • Постов: 6
  • Репутация: -2
и это все пусть сделает НУЦ, на своем доверенном ЖЕЛЕЗЕ и ПО, а нам передает какие ниубдь callbackи, ввиде JS, или API как это делают epay

p.s Ребята из НУЦ вы там ваще чем занимаетесь ? это все должно от вас исходить.... как мнимим если у сами неполучается то создавать тусовки и обсуждать и решать, я считаю прямая отвественность в НЕРАЗВИТИи у нас ЭЦП и всей геморности напрямую зависит от ВАС

Re: Реализация на javascript 1 год, 8 мес. назад #3575

  • vprokof
  • Осваиваюсь на форуме
  • Постов: 28
  • Репутация: 0
Нужно брать во внимание, что НУЦ является заложником устаревших технологий времён Windows XP и локальных сетей, когда интернет был в диковинку, а мобильник мог позволить себе только миллионер. Гиганты информационной индустрии всеми силами выдавливают устаревшие технологии. Устарело в первую очередь законодательство , которое заставляет технических специалистов выискивать соломинки, чтобы не утонуть окончательно.

У нас хоть единый удостоверяющий центр. В России ситуация ещё хуже. Там наплодили множество коммерческих удостоверяющих центров, которые мало того, что не связаны между собой, да ещё выдают сертификаты за деньги. Когда эти центры пришли просить денег на развитие, в правительстве России им отказали с формулировкой, что есть более современные решения. Легко предположить, что это блокчейн, поскольку выражение "цепочка сертификатов" содержит внутри себя это слово.

Но поскольку будущее у нас ещё не наступило, предлагаем сформировать общественное мнение вокруг следующих тезисов.

1) Допустимо иметь зелёный https:// для реализации безопасного соединения между клиентом и сервером по сертификату от удостоверяющих центров, расположенных за пределами РК. Банки у нас пользуются зелёным ключами, значит и остальным можно. Когда простой пользователь видит красный https:// на удостоверяющем центре у него происходит разрыв шаблона. Советы импортировать корневой и промежуточный сертификаты в хранилище ключей для большинства простых пользователей выше их понимания. Иногда импорт просто не работает по непонятным причинам.

2) Допустимо передавать ЭЦП с клиента на сервер внутри зелёного https:// для операций, которые используют только оперативную память сервера.
Неважно, какими способами получен этот зелёный https:// .
Главное, чтобы было безопасное соединение внутри которого можно передавать ключи ЭЦП для проверки на сервере.

Нужно разделить внешние и внутренние технологии. Все остальные проблемы решаются в рамках и нынешних и будущих технологий.
Изменено: 1 год, 8 мес. назад от vprokof.

Re: Реализация на javascript 1 год, 8 мес. назад #3579

  • tjunussov
  • Новый участник
  • Постов: 6
  • Репутация: -2
Тут я согласен, с вами, давайте дальше попробуем обсудить эту тему
-- с зелененькими https, с одной стороны есть опасение что зеленые сертификаты подконтрольны не нашему государству, пусть работают в 2х режимах ( с нашим и ненашим корневыми сертами )
-- даже если https будет с забугорным зеленным сертом, то внутри сами запросы/данные будут подписаны нашим сертом, и если подумать вроде недолжно быть проблем с подделкой ? всвякие MITM атаки не проканают
-- насчет Вашего 2го пункта, я бы доверил эту вещь только НУЦу ( ну или любой другой гос организации, где есть строгий порядок, доступ к такому серверу итд ) и ввел понятие ПОЛУ ПОДПИСЬ ( может по другому назвать ), такая подпись которая может подписывать не все документы ( продажа имущества, и другие важные вещи нельзя будет подписать данным методом )

Мне кажется надо увеличить кол-во опции в подписи/авторизации различными видами как :
- паролевый вариант
- Одноразовых Текстовых Токенов ( на подобии банка ) для мелких авторизационных нужд и подписей
- OTP токенов хардвейрных ( тоже как в некоторых банках ) для мелких авторизационных нужд
- Cloud ЭЦП вариант ( другой вид ключа ) для средних видов авторизации
- Телепортированных ЭЦП ( это вот ваш 2й вариант ) для средних видов авторизации
- ПолуТелепортированный ЭЦП ( это когда все произойдет внутри браузера клиента ) для средних видов авторизации
- JavaToken - версии 3.0, когда внутри флешки развернут вебсервер, и с помощью REST API можно делать подписи
Дополнительные виды доп авторизации :
- дополнительно ко всем видам можно/нужно внести доп токеновую авторизацию с помощью SMS/USSD/Bot/IVR
- с помощью EGOV(или НУЦ) app, возможность создания токена на базе встроеного в приложение ( вкаченого ) ЭЦП
ps. это бы повзолило еще больше повысить безопасность )

Re: Реализация на javascript 1 год, 8 мес. назад #3580

  • vprokof
  • Осваиваюсь на форуме
  • Постов: 28
  • Репутация: 0
Цитата
- насчет Вашего 2го пункта, я бы доверил эту вещь только НУЦу ( ну или любой другой гос организации, где есть строгий порядок, доступ к такому серверу и т.д )
Конец цитаты.

НУЦ постоянно просят добавить ту или иную функцию в NCALayer.
Список огромен. Если этот список пожеланий будет предъявлен НУЦу для реализации в Service‑oriented architecture (SOA)
всё закончится печально.
Изменено: 1 год, 8 мес. назад от vprokof.
  • Страница:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
FaLang translation system by Faboba