Безопасно ли использовать Environ ("Имя пользователя") в качестве метода аутентификации в MS Access/Active Directory?

Я разрабатываю приложение в среде нашей небольшой компании. Это наша установка в двух словах:

  • Сотрудники входят в свои ПК через свою учетную запись Active Directory.
  • Приложение, которое я разрабатываю, использует MS Access в качестве интерфейса и MS SQL Server 2019 в качестве сервера (режим аутентификации Windows).

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

Вот что я придумал:

tblEmployees:

ID сотрудника Имя сотрудника ADВход 1 Джон Доу КОМПАНИЯ\john.doe 2 Питер Уилсон КОМПАНИЯ\peter.wilson

Когда любой пользователь запускает приложение MS Access, при запуске оно делает что-то вроде этого:

Private Sub Form_Load()

    Dim rsUser As Recordset
    Dim intEmployeeID As Integer
    Dim strEmployeeName As String
    
    Set rsUser = CurrentDb.OpenRecordset("SELECT * FROM tblEmployees", dbOpenSnapshot, dbReadOnly)
    rsUser.FindFirst "ADLogin='" & Environ("USERDOMAIN") & "\" & Environ("USERNAME") & "'"
    
    If rsUser.NoMatch Then
    
        ' User does not have access to the application
        rsUser.Close
        Set rsUser = Nothing
        
        Application.Quit
        
    Else
    
        ' User with this AD Login has been found and that means that he does have access
        intEmployeeID = rsUser("EmployeeID")
        strEmployeeName = rsUser("EmployeeName")
        
        TempVars("EmployeeID") = intEmployeeID
        TempVars("EmployeeName") = strEmployeeName
        
        
        DoCmd.OpenForm "frm_MainMenu"
        Forms!frm_MainMenu.Requery
        DoCmd.Close acForm, Me.Name, acSaveYes
        
        Forms!frm_MainMenu!txtLoggedUser = TempVars("EmployeeName")
        
    End If

    rsUser.Close
    Set rsUser = Nothing
    
End Sub

Затем я буду использовать TempVars("EmployeeID") во всем приложении, чтобы сделать формы и кнопки доступными и так далее.

Мой вопрос: это хорошая практика? Это безопасно? Возможно, есть лучший способ сделать это? Спасибо за любые советы.

Определенно не безопасно (представьте, что произойдет, если пользователь отключит VBA). Почему бы просто не обрабатывать аутентификацию на бэкэнде SQL-сервера?\

Erik A 20.04.2023 14:21

Идея здесь состоит в том, чтобы обеспечить безопасность как на переднем, так и на заднем конце. Внутренняя безопасность не позволит мне предоставить пользователю доступ к функциям Access, а только к самим данным. Простите, а что вы подразумеваете под "пользователь отключает VBA"?

ThomassoCZ 20.04.2023 14:36

В реестре вы можете отключить VBA, а затем открыть базы данных Access. Любой содержащийся в них VBA не будет работать.

Erik A 20.04.2023 14:37

Я могу отключить доступ к реестру через GPO

ThomassoCZ 20.04.2023 14:44

Затем они могут изменить реестр через VBA. Или переместите его на другой компьютер с помощью USB-накопителей/почты/и т. д., затем выньте часть VBA. Вам действительно нужно позаботиться о защите данных на стороне сервера, в VBA он всегда будет в лучшем случае частично безопасным (и маршрут environ известен как действительно небезопасный, поскольку эти переменные легко модифицируются)

Erik A 20.04.2023 15:01
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
94
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Прежде всего позвольте мне начать с того, что Access не является безопасным, но это зависит от знаний ваших коллег и от того, насколько далеко они готовы зайти.

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

См. пример:

Запрос (ваши поля могут отличаться, но вы поняли идею)

PARAMETERS [Domain] Text (50), [Username] Text (50);
SELECT *
FROM T
WHERE T.Domain=[Domain] AND T.Username=[Username];

Вы также можете создать временный запрос из кода.

Const SQL As String = "The SQL command above"

'No query name means it's temporary and will be deleted once the method runs.
Dim q As DAO.QueryDef
Set q = CurrentDb().CreateQueryDef("", SQL) 

Чтобы вызвать его и проверить зарегистрированного пользователя:

Dim q As DAO.QueryDef
Dim r As DAO.Recordset

Set q = CurrentDb().QueryDefs("YourQueryName")

'Using the Environ() method.
q.Parameters("[Domain]").Value = Environ("USERDOMAIN")
q.Parameters("[Username]").Value = Environ("USERNAME")

'OR alternative method to get the username/domain from @Andre in comments
'This is more secure than the Environ() method.
With CreateObject("WScript.Network")
    q.Parameters("[Domain]").Value = .UserDomain
    q.Parameters("[Username]").Value = .UserName
End With

'read-only, no need for changes.    
Set r = q.OpenRecordset(dbOpenSnapshot)

'Not found
If r.EOF Then
    DoCmd.Quit acQuitPrompt
    Exit Sub
End If

'Found
'The recordset now contains whatever fields the query selected.
'Do what needs to be done.
'...

'Clean up
If Not r Is Nothing Then r.Close
If Not q Is Nothing Then q.Close

Наконец, я бы изменил переменную intEmployeeID на тип Long и добавил бы в метод обработку ошибок.

Как минимум, вы можете использовать не Environ для получения имени пользователя и домена, а что-то более безопасное, как указано здесь.

Erik A 20.04.2023 15:53

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

Kostas K. 20.04.2023 16:01

Вам не нужен вызов API, см. stackoverflow.com/a/32565953/3820271

Andre 20.04.2023 16:31

Спасибо, Костас, это логично. Однако могу я спросить, в чем преимущество запроса Access по сравнению с получением данных через набор записей? Я пытаюсь сохранить интерфейс как можно более чистым, в настоящее время у меня нет локальных запросов. На данный момент все обрабатывается через представления SQL Server. Заранее спасибо за разъяснения :)

ThomassoCZ 21.04.2023 09:32

Конкатенация строк и параметры, и вы сразу возвращаете только нужную запись (или ничего). Вам не нужно иметь статический запрос, но создайте его на лету из кода. Смотрите это: stackoverflow.com/questions/74078962/…

Kostas K. 21.04.2023 10:18

@ThomassoCZ Добавлен пример временного запроса.

Kostas K. 21.04.2023 10:32

Другие вопросы по теме