Ошибка: не удалось расшифровать ключ, поскольку ключ сеанса изменился | shinyapps.io | р - PullRequest
0 голосов
/ 06 марта 2020

Примечание. Этот (длинный) вопрос является продолжением моего предыдущего сообщения .

Я хотел бы добиться шифрования данных локально (локальный RStudio) и удаленно расшифровать зашифрованные данные (приложение, размещенное на shinyapps.io) .

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

Однако при публикации в shinyapps.io (облачный хостинг) выдает ошибку , как показано ниже:

enter image description here

1.Код для шифрования фрейма данных.

library(sodium)
#> Warning: package 'sodium' was built under R version 3.5.3
library(encryptr)
#> Warning: package 'encryptr' was built under R version 3.5.3
library(cyphr)
#> Warning: package 'cyphr' was built under R version 3.5.3
#> 
#> Attaching package: 'cyphr'
#> The following objects are masked from 'package:encryptr':
#> 
#>     decrypt, decrypt_file, encrypt, encrypt_file

#setting local working directory 
#setwd("D://Work/03Mar20/")

df = data.frame(
  user = c("user1", "user2", "user3", "user4", "user5"),
  password = c("pass1", "pass2", "pass3", "pass4", "pass5"),
  permissions = c("admin","admin","admin","admin","admin"),
  name = c("user one", "user two", "user three", "user four", "user five"),
  stringsAsFactors = FALSE
)

#generating a key and encrypting the desired dataframe using cyphr and sodium packages
key <- cyphr::key_sodium(sodium::keygen())
cyphr::encrypt(saveRDS(df, "auth_base.rds"), key)

#saving the key as a .rds file and removing from R environment
saveRDS(key, "key.rds")
rm(key)


Created on 2020-03-06 by the reprex package (v0.3.0)

2.Код для блестящего приложения (дешифрование фрейма данных и авторизация пользователей) .

library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyauthr)
library(shinyjs)
library(sodium)
library(encryptr)
library(cyphr)
library(glue)
library(knitr)
library(rsconnect)
library(ggplot2)
library(DT)

#setting local working directory 
#setwd("D://Work Related/03Mar20")

key <- readRDS("key.rds")
df = cyphr::decrypt(readRDS("auth_base.rds"), key)

#Dataframe that holds usernames, passwords and other user data
credentials = data.frame(
    username = df$user,
    password = sapply(df$password, sodium::password_store),
    permission = df$permissions, 
    name = df$name,
    stringsAsFactors = FALSE
)

# Main login screen
loginpage <- div(id = "loginpage", style = "width: 500px; max-width: 100%; margin: 0 auto; padding: 20px;",
                 wellPanel(
                     tags$h2("LOG IN", class = "text-center", style = "padding-top: 0;color:#333; font-weight:600;"),
                     textInput("userName", placeholder="Username", label = tagList(icon("user"), "Username")),
                     passwordInput("passwd", placeholder="Password", label = tagList(icon("unlock-alt"), "Password")),
                     br(),
                     div(
                         style = "text-align: center;",
                         actionButton("login", "SIGN IN", style = "color: white; background-color:#3c8dbc;
                                 padding: 10px 15px; width: 150px; cursor: pointer;
                                 font-size: 18px; font-weight: 600;"),
                         shinyjs::hidden(
                             div(id = "nomatch",
                                 tags$p("Incorrect username or password!",
                                        style = "color: red; font-weight: 600; 
                                            padding-top: 5px;font-size:16px;", 
                                        class = "text-center"))),
                         br()
                     ))
)

header <- dashboardHeader( title = "Template", uiOutput("logoutbtn"))
sidebar <- dashboardSidebar(collapsed = FALSE, uiOutput("sidebarpanel")) 
body <- dashboardBody(shinyjs::useShinyjs(), uiOutput("body"))

ui<-dashboardPage(header, sidebar, body, skin = "blue")

server <- function(input, output, session) {

    login = FALSE
    USER <- reactiveValues(login = login)

    observe({ 
        if (USER$login == FALSE) {
            if (!is.null(input$login)) {
                if (input$login > 0) {
                    Username <- isolate(input$userName)
                    Password <- isolate(input$passwd)
                    if(length(which(credentials$username==Username))==1) { 
                        pasmatch  <- credentials["password"][which(credentials$username==Username),]
                        pasverify <- password_verify(pasmatch, Password)
                        if(pasverify) {
                            USER$login <- TRUE
                        } else {
                            shinyjs::toggle(id = "nomatch", anim = TRUE, time = 1, animType = "fade")
                            shinyjs::delay(3000, shinyjs::toggle(id = "nomatch", anim = TRUE, time = 1, animType = "fade"))
                        }
                    } else {
                        shinyjs::toggle(id = "nomatch", anim = TRUE, time = 1, animType = "fade")
                        shinyjs::delay(3000, shinyjs::toggle(id = "nomatch", anim = TRUE, time = 1, animType = "fade"))
                    }
                } 
            }
        }    
    })

    output$logoutbtn <- renderUI({
        req(USER$login)
        tags$li(a(icon("fa fa-sign-out"), "Logout", 
                  href="javascript:window.location.reload(true)"),
                class = "dropdown", 
                style = "background-color: #eee !important; border: 0;
                    font-weight: bold; margin:5px; padding: 10px;")
    })

    output$sidebarpanel <- renderUI({
        if (USER$login == TRUE ){ 
            if (credentials[,"permission"][which(credentials$username==input$userName)]=="admin") {
                sidebarMenu(
                    div(textOutput("permission"), style = "padding: 20px"),
                    menuItem("Data", tabName = "dashboard", icon = icon("table"))
                    )
            }
        }
    })



    output$body <- renderUI({
        if (USER$login == TRUE ) {
            if (credentials[,"permission"][which(credentials$username==input$userName)]=="admin") {
                tabItems(
                    tabItem(
                        tabName ="dashboard", class = "active",
                        fluidRow(
                            box(width = 12, dataTableOutput('results'))
                        ))
                )
            }

        }
        else {
            loginpage
        }
    })

    output$permission <- renderText({
        if (USER$login == TRUE ) {
            paste("Permission: ", credentials[,"permission"][which(credentials$username==input$userName)])
        }    
    })

    output$results <-  DT::renderDataTable({
        datatable(mtcars, options = list(autoWidth = TRUE,
                                         searching = FALSE))
    })

}

shinyApp(ui, server)

Из ошибки я узнаю, что идентификатор сеанса key во время шифрования не совпадает, когда я публикую sh его в облаке для расшифровки. Как ладья ie в области безопасности, есть ли обходной путь для расшифровки в облаке?

Любые предложения очень ценятся.

1 Ответ

2 голосов
/ 11 марта 2020

Причина проблемы

Проблема по проекту , так как cyphr::key_sodium создает ключ, который действителен, в общем, только для текущего сеанса. То есть невозможно разделить его между разными сеансами, не говоря уже о разных системах.

Следовательно, проблема вовсе не связана с самим shiny, а с тем фактом, что вы пытаетесь использовать клавиши cyphr в разных сеансах.

Из виньетки:

При использовании key_openssl, keypair_openssl, key_sodium или keypair_sodium мы генерируем что-то, что может расшифровать данные. Объекты, возвращаемые этими функциями, могут шифровать и дешифровать данные, поэтому разумно опасаться, что, если бы эти объекты сами были сохранены на диск, ваши данные были бы скомпрометированы.

Во избежание этого cyphr не сохраняет закрытые или симметричные c ключи непосредственно в этих объектах, но вместо этого шифруют секретные ключи с помощью специфического для cyphr c сеансового ключа, который создается заново при каждой загрузке пакета. Это означает, что объекты практически полезны только в течение одного сеанса, и если они сохранены с помощью save.image (возможно, автоматически в конце сеанса), ключи не могут быть использованы для расшифровки данных.

Представление о проблеме

library(cyphr)

file <- "encr.rds"
df <- data.frame(a = 1) 

## cyphr workflow won't work across sessions / systems

key <- key_sodium(sodium::keygen())

encrypt(saveRDS(df, file), key)

## works within the same session
decrypt(readRDS(file), key)

## simulate session change (restart or other system)
session_key_refresh()

## won't work
decrypt(readRDS(file), key)
unlink(file)

Решение


Примечание. Обновлен код, поскольку он не требуется для сохраните и сохраните nonce.


Таким образом, вам нужно использовать другую библиотеку для выполнения работы. Например, вы можете использовать саму библиотеку sodium:

library(sodium)
key_file <- "key.rds"
file <- "encr.rds"
key <- keygen()

df <- data.frame(a = 1)
msg <- serialize(df, NULL)

cipher <- data_encrypt(msg, key)
saveRDS(cipher, file)

## store key
saveRDS(key, key_file)

Теперь вы можете поделиться key.rds (или поместить ее на свой блестящий сервер). Чтобы смоделировать это, просто перезапустите R и запустите:

library(sodium)
key_file <- "key.rds"
file <- "encr.rds"
key <- readRDS(key_file)

# Decrypt with same stored key and nonce
decipher <- readRDS(file)
unserialize(data_decrypt(decipher, key))

#   a
# 1 1

unlink(key_file)
unlink(file)

Проблемы безопасности

Использование шифрования симметрии c (это один ключ для де-/ шифрования , как в вашем примере) и хранение ключа сверху на сервере не звучит как хорошая идея. Любой, кто заполучит ваш файл ключей, сможет расшифровать ваши секреты.

Я сам не специалист по безопасности, но я бы пересмотрел ваш дизайн.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...